Tüm Platformlar için Hızlı Uygulama Geliştirme Kitabı... Delphi
Ön Sipariş Talebinde Bulunan Üyelerimiz
Sipariş Talebinde Bulunan Üyelerimiz

Konuyu Paylaş : facebook gplus twitter

Konuyu Oyla:
  • Derecelendirme: 5/5 - 1 oy
  • 1
  • 2
  • 3
  • 4
  • 5
[ÇÖZÜLDÜ Kısmen]Trigger ile Başka Database çinde Shadow Copy oluşturma
#1
Merhaba

Elimde uygulama için kullandığım bir veri tabanı var ve içinde bir sürü tablo var. Bu veri tabanının birden fazla farklı uygulama için kullanımları var fakat yapı olarak birebir aynı veri tabanı.

Ben bu tablolarda silme veya değişiklik yapıldığında bir kopyasını log olarak tutmak istiyorum.

Bende şöyle bir yol izlemeyi planladım. Log için bir tane veri tabanı oluşturup. Daha sonra bunun içinde PostgreSQL in güzel bir özelliği olan schema ile her farklı uygulama için bir schema açıp bu veri tabanı içinde logları toplu halde tutmak istiyorum.

Log işlemini aynı veri tabanı içinde olursa aşağıdaki kod ile sorunsuz işlemi yapabiliyorum. Hangi tablo olursa olsun direkt olarak OLD içindeki tablo verisini direkt olarak tablo adı bilgisi ile INSERT ediyor.

 EXECUTE format('INSERT INTO %I.%I VALUES ($1.*)', (SELECT current_database()), TG_TABLE_NAME)
USING OLD;
RETURN OLD;

Farklı veritabanı içinde tutmak istediğimde ise bir yerde takıldım ve buna ek olarak farklı görüş ve fikirlere de açığım. Her tablo için farklı trigger ler yazabilirim fakat bu çok fazla amatör ve zaman gerektiren bir işlem daha sonra da bir güncelleme yapılmak istenirse buda çok fazla zaman alır.

_old_val := (SELECT array[OLD.*]);  --OLD içindeki bilgiyi bir şekilde parse edip 'ELMA', 'ARMUT', 'PATATES' gibi ayırmam gerekiyor
_sql := (SELECT format('INSERT INTO %I.%I VALUES (%L, %L, %L)', _database, TG_TABLE_NAME, _username, _ip, _old_val));
PERFORM dblink('host=localhost user=postgres password=123 dbname=ths_erp_log port=5432', '' || _sql);
Yukarıdaki _old_var değişkenin sonucu aşağıdaki gibi geliyor. Arada null olan bilgiler var. Bunlarda direkt virgül var hiç bir şey yazmıyor.

ERROR: SQL=INSERT INTO ths_erp2017.cins_ozelligi VALUES ('THS_ADMIN', '127.0.0.1/32', E'{"(13,t,1,PANOFONK,\\"TABLO FONKSİYON\\",ANAKART,HABERLEŞME,TAHRİK,\\"BASİT KUMANDA\\",\\"AŞAĞI TOPLAMA\\",\\"ÇİFT DÜĞME\\",,,,\\"ASANSÖR STANDART\\",,SERİ,f)"}')I'.

Asıl olaması gereken durum ise
INSERT INTO ths_erp2017.cins_ozelligi VALUES ('THS_ADMIN', '127.0.0.1/32', 13,t,1,'PANOFONK', 'TABLO FONKSİYON', 'ANAKART', 'HABERLEŞME', 'TAHRİK', 'BASİT KUMANDA', 'AŞAĞI TOPLAMA', 'ÇİFT DÜĞME', NULL, NULL, NULL, 'STANDART', NULL, 'SERİ', f);
OLD içindeki bilgiyi birşekilde parse edebilirsem hiç bir derdim kalmayacak sorunsuz olarak farklı bir veri tabanı içinde herhangi bir tablo için shadow copy işlemini yapmış olacağım.
OLD yerine trigger içinde işlem yapılan tablo belli o tablo içeriğini de alabilirim.
 
EXECUTE format('SELECT * FROM %I WHERE %s=%s', TG_TABLE_NAME, TG_TABLE_NAME || '.id', OLD.id)
 Fakat asıl veriyi işleyip tırnakla ayrılmış text gibi dönüştürmem ve _old_val içinde bu bilgiyi göndermem gerekiyor.


Biraz karışık oldu galiba
PostgreSQL - Linux - Delphi, Linkleri Görebilmeniz İçin Giriş yap veya Üye Ol
WWW
Cevapla
#2
Özel bir nedeni yoksa replication kullanmanızı öneririm.

Konu hakkında tecrübem olduğu için şunu söyleyebilirim , farklı databaselerde sorun yaşıyor sunuz ileride özellikle farklı serverlarda yedekleme yapacaksanız kendi yazdığınız kodda kafanız çok ağrıyacak hazırlıklı olun
Yalnızım ama bir kente yürüyen ordu gibiyim, edebiyattan kaçınmalıyım..
Cevapla
#3
(20-07-2018, Saat: 22:14)narkotik Adlı Kullanıcıdan Alıntı: Linkleri Görebilmeniz İçin Giriş yap veya Üye OlÖzel bir nedeni yoksa replication kullanmanızı öneririm.

Konu hakkında tecrübem olduğu için şunu söyleyebilirim , farklı databaselerde sorun yaşıyor sunuz ileride  özellikle farklı serverlarda yedekleme yapacaksanız kendi yazdığınız kodda kafanız çok ağrıyacak hazırlıklı olun

Hayır ben silinen kayıtların ve değiştirilen kayıtların geçmişini tutacağım kim tarafından, hangi bilgi ve ne zaman değiştirilmiş. Replication  amacı ve mantığı farklı ve benim işimi görmez.
PostgreSQL - Linux - Delphi, Linkleri Görebilmeniz İçin Giriş yap veya Üye Ol
WWW
Cevapla
#4
(20-07-2018, Saat: 21:00)3ddark Adlı Kullanıcıdan Alıntı: Linkleri Görebilmeniz İçin Giriş yap veya Üye OlMerhaba

Elimde uygulama için kullandığım bir veri tabanı var ve içinde bir sürü tablo var. Bu veri tabanının birden fazla farklı uygulama için kullanımları var fakat yapı olarak birebir aynı veri tabanı.

Ben bu tablolarda silme veya değişiklik yapıldığında bir kopyasını log olarak tutmak istiyorum.

Bende şöyle bir yol izlemeyi planladım. Log için bir tane veri tabanı oluşturup. Daha sonra bunun içinde PostgreSQL in güzel bir özelliği olan schema ile her farklı uygulama için bir schema açıp bu veri tabanı içinde logları toplu halde tutmak istiyorum.

Log işlemini aynı veri tabanı içinde olursa aşağıdaki kod ile sorunsuz işlemi yapabiliyorum. Hangi tablo olursa olsun direkt olarak OLD içindeki tablo verisini direkt olarak tablo adı bilgisi ile INSERT ediyor.

 EXECUTE format('INSERT INTO %I.%I VALUES ($1.*)', (SELECT current_database()), TG_TABLE_NAME)
USING OLD;
RETURN OLD;

Farklı veritabanı içinde tutmak istediğimde ise bir yerde takıldım ve buna ek olarak farklı görüş ve fikirlere de açığım. Her tablo için farklı trigger ler yazabilirim fakat bu çok fazla amatör ve zaman gerektiren bir işlem daha sonra da bir güncelleme yapılmak istenirse buda çok fazla zaman alır.

_old_val := (SELECT array[OLD.*]);  --OLD içindeki bilgiyi bir şekilde parse edip 'ELMA', 'ARMUT', 'PATATES' gibi ayırmam gerekiyor
_sql := (SELECT format('INSERT INTO %I.%I VALUES (%L, %L, %L)', _database, TG_TABLE_NAME, _username, _ip, _old_val));
PERFORM dblink('host=localhost user=postgres password=123 dbname=ths_erp_log port=5432', '' || _sql);
Yukarıdaki _old_var değişkenin sonucu aşağıdaki gibi geliyor. Arada null olan bilgiler var. Bunlarda direkt virgül var hiç bir şey yazmıyor.

ERROR: SQL=INSERT INTO ths_erp2017.cins_ozelligi VALUES ('THS_ADMIN', '127.0.0.1/32', E'{"(13,t,1,PANOFONK,\\"TABLO FONKSİYON\\",ANAKART,HABERLEŞME,TAHRİK,\\"BASİT KUMANDA\\",\\"AŞAĞI TOPLAMA\\",\\"ÇİFT DÜĞME\\",,,,\\"ASANSÖR STANDART\\",,SERİ,f)"}')I'.

Asıl olaması gereken durum ise
INSERT INTO ths_erp2017.cins_ozelligi VALUES ('THS_ADMIN', '127.0.0.1/32', 13,t,1,'PANOFONK', 'TABLO FONKSİYON', 'ANAKART', 'HABERLEŞME', 'TAHRİK', 'BASİT KUMANDA', 'AŞAĞI TOPLAMA', 'ÇİFT DÜĞME', NULL, NULL, NULL, 'STANDART', NULL, 'SERİ', f);
OLD içindeki bilgiyi birşekilde parse edebilirsem hiç bir derdim kalmayacak sorunsuz olarak farklı bir veri tabanı içinde herhangi bir tablo için shadow copy işlemini yapmış olacağım.
OLD yerine trigger içinde işlem yapılan tablo belli o tablo içeriğini de alabilirim.
 
EXECUTE format('SELECT * FROM %I WHERE %s=%s', TG_TABLE_NAME, TG_TABLE_NAME || '.id', OLD.id)
 Fakat asıl veriyi işleyip tırnakla ayrılmış text gibi dönüştürmem ve _old_val içinde bu bilgiyi göndermem gerekiyor.


Biraz karışık oldu galiba

-- Function: public.audit()

-- DROP FUNCTION public.audit();

CREATE OR REPLACE FUNCTION public.audit() RETURNS trigger AS
$BODY$
declare
_username varchar;
_ip varchar;
_database varchar;
_sql text;
_old_val text[];
_test text;
_tarih timestamp without time zone;
BEGIN

IF (TG_OP = 'INSERT') OR (TG_OP = 'DELETE') OR ((TG_OP = 'UPDATE') AND (ARRAY[OLD] <> ARRAY[NEW])) THEN

_username := (upper(session_user)); 
_ip := (inet_client_addr());
_database := (SELECT current_database());
_tarih := (SELECT NOW());

IF (TG_OP = 'INSERT') THEN
_old_val := (SELECT array[NEW]);
ELSE
_old_val := (SELECT array[OLD]);
END IF;

_test := (SELECT array_to_string(_old_val, ', '));

_test := replace(_test, ',,', ', null,');
_test := replace(_test, ',,', ', null,');
_test := replace(_test, ',,', ', null,');
_test := replace(_test, ',,', ', null,');
_test := replace(_test, ',,', ', null,');
_test := replace(_test, ',,', ', null,');
_test := replace(_test, ',,', ', null,');
_test := replace(_test, ',', ''', ''');
_test := replace(_test, '"', '''');
_test := replace(_test, '''''', '''');
_test := replace(_test, '(', '''');
_test := replace(_test, ')', '''');
_test := replace(_test, ''' null''', ' null');

_sql := (SELECT format('INSERT INTO %I.%I VALUES (%L, %L, %L, %L, %s)', _database, TG_TABLE_NAME, _username, _ip, _tarih, TG_OP, _test));

PERFORM dblink(
'host=localhost user=postgres password=123 dbname=ths_erp_log port=5432', 
' ' || _sql || ';'
);

END IF;

RETURN NULL;

END
$BODY$
 LANGUAGE plpgsql VOLATILE COST 100;
ALTER FUNCTION public.audit() OWNER TO postgres;

Kısmen çözüldü. Acemice bir kod oldu. Fakat bir şekilde şimdilik çalışıyor gibi. Veriyi bir string e çevirip gerekli dönüşümleri yapınca istediğim sonucu verdi.
PostgreSQL - Linux - Delphi, Linkleri Görebilmeniz İçin Giriş yap veya Üye Ol
WWW
Cevapla
#5
(21-07-2018, Saat: 15:47)3ddark Adlı Kullanıcıdan Alıntı: Linkleri Görebilmeniz İçin Giriş yap veya Üye Ol
(20-07-2018, Saat: 21:00)3ddark Adlı Kullanıcıdan Alıntı: Linkleri Görebilmeniz İçin Giriş yap veya Üye OlMerhaba

Elimde uygulama için kullandığım bir veri tabanı var ve içinde bir sürü tablo var. Bu veri tabanının birden fazla farklı uygulama için kullanımları var fakat yapı olarak birebir aynı veri tabanı.

Ben bu tablolarda silme veya değişiklik yapıldığında bir kopyasını log olarak tutmak istiyorum.

Bende şöyle bir yol izlemeyi planladım. Log için bir tane veri tabanı oluşturup. Daha sonra bunun içinde PostgreSQL in güzel bir özelliği olan schema ile her farklı uygulama için bir schema açıp bu veri tabanı içinde logları toplu halde tutmak istiyorum.

Log işlemini aynı veri tabanı içinde olursa aşağıdaki kod ile sorunsuz işlemi yapabiliyorum. Hangi tablo olursa olsun direkt olarak OLD içindeki tablo verisini direkt olarak tablo adı bilgisi ile INSERT ediyor.

 EXECUTE format('INSERT INTO %I.%I VALUES ($1.*)', (SELECT current_database()), TG_TABLE_NAME)
USING OLD;
RETURN OLD;

Farklı veritabanı içinde tutmak istediğimde ise bir yerde takıldım ve buna ek olarak farklı görüş ve fikirlere de açığım. Her tablo için farklı trigger ler yazabilirim fakat bu çok fazla amatör ve zaman gerektiren bir işlem daha sonra da bir güncelleme yapılmak istenirse buda çok fazla zaman alır.

_old_val := (SELECT array[OLD.*]);  --OLD içindeki bilgiyi bir şekilde parse edip 'ELMA', 'ARMUT', 'PATATES' gibi ayırmam gerekiyor
_sql := (SELECT format('INSERT INTO %I.%I VALUES (%L, %L, %L)', _database, TG_TABLE_NAME, _username, _ip, _old_val));
PERFORM dblink('host=localhost user=postgres password=123 dbname=ths_erp_log port=5432', '' || _sql);
Yukarıdaki _old_var değişkenin sonucu aşağıdaki gibi geliyor. Arada null olan bilgiler var. Bunlarda direkt virgül var hiç bir şey yazmıyor.

ERROR: SQL=INSERT INTO ths_erp2017.cins_ozelligi VALUES ('THS_ADMIN', '127.0.0.1/32', E'{"(13,t,1,PANOFONK,\\"TABLO FONKSİYON\\",ANAKART,HABERLEŞME,TAHRİK,\\"BASİT KUMANDA\\",\\"AŞAĞI TOPLAMA\\",\\"ÇİFT DÜĞME\\",,,,\\"ASANSÖR STANDART\\",,SERİ,f)"}')I'.

Asıl olaması gereken durum ise
INSERT INTO ths_erp2017.cins_ozelligi VALUES ('THS_ADMIN', '127.0.0.1/32', 13,t,1,'PANOFONK', 'TABLO FONKSİYON', 'ANAKART', 'HABERLEŞME', 'TAHRİK', 'BASİT KUMANDA', 'AŞAĞI TOPLAMA', 'ÇİFT DÜĞME', NULL, NULL, NULL, 'STANDART', NULL, 'SERİ', f);
OLD içindeki bilgiyi birşekilde parse edebilirsem hiç bir derdim kalmayacak sorunsuz olarak farklı bir veri tabanı içinde herhangi bir tablo için shadow copy işlemini yapmış olacağım.
OLD yerine trigger içinde işlem yapılan tablo belli o tablo içeriğini de alabilirim.
 
EXECUTE format('SELECT * FROM %I WHERE %s=%s', TG_TABLE_NAME, TG_TABLE_NAME || '.id', OLD.id)
 Fakat asıl veriyi işleyip tırnakla ayrılmış text gibi dönüştürmem ve _old_val içinde bu bilgiyi göndermem gerekiyor.


Biraz karışık oldu galiba

-- Function: public.audit()

-- DROP FUNCTION public.audit();

CREATE OR REPLACE FUNCTION public.audit() RETURNS trigger AS
$BODY$
declare
_username varchar;
_ip varchar;
_database varchar;
_sql text;
_old_val text[];
_test text;
_tarih timestamp without time zone;
BEGIN

IF (TG_OP = 'INSERT') OR (TG_OP = 'DELETE') OR ((TG_OP = 'UPDATE') AND (ARRAY[OLD] <> ARRAY[NEW])) THEN

_username := (upper(session_user)); 
_ip := (inet_client_addr());
_database := (SELECT current_database());
_tarih := (SELECT NOW());

IF (TG_OP = 'INSERT') THEN
_old_val := (SELECT array[NEW]);
ELSE
_old_val := (SELECT array[OLD]);
END IF;

_test := (SELECT array_to_string(_old_val, ', '));

_test := replace(_test, ',,', ', null,');
_test := replace(_test, ',,', ', null,');
_test := replace(_test, ',,', ', null,');
_test := replace(_test, ',,', ', null,');
_test := replace(_test, ',,', ', null,');
_test := replace(_test, ',,', ', null,');
_test := replace(_test, ',,', ', null,');
_test := replace(_test, ',', ''', ''');
_test := replace(_test, '"', '''');
_test := replace(_test, '''''', '''');
_test := replace(_test, '(', '''');
_test := replace(_test, ')', '''');
_test := replace(_test, ''' null''', ' null');

_sql := (SELECT format('INSERT INTO %I.%I VALUES (%L, %L, %L, %L, %s)', _database, TG_TABLE_NAME, _username, _ip, _tarih, TG_OP, _test));

PERFORM dblink(
'host=localhost user=postgres password=123 dbname=ths_erp_log port=5432', 
' ' || _sql || ';'
);

END IF;

RETURN NULL;

END
$BODY$
 LANGUAGE plpgsql VOLATILE COST 100;
ALTER FUNCTION public.audit() OWNER TO postgres;

Kısmen çözüldü. Acemice bir kod oldu. Fakat bir şekilde şimdilik çalışıyor gibi. Veriyi bir string e çevirip gerekli dönüşümleri yapınca istediğim sonucu verdi.

Benim çözümüm istediğiniz db ve tablo üzerinde ihtiyacınız olan trigger'ı dinamik olarak create eden bir tool yazıp, her bir kayıt için tarih ve ondalıklı sayıları sabit bir formatta string olarak to_date(... to_number(.... içinde formatlarınızı yazarak client'lardaki tarih ve ondalık ya da binlik ayıraçlardan etkilenmeyecek scriptler haline getirip, bunları istediğiniz sıklıkta çalışacak bir tool ile aktarımını yapmak.
Cevapla
#6
Şu linkteki anlatım işinizi görür mü?

Linkleri Görebilmeniz İçin Giriş yap veya Üye Ol
Peyami Safa: "Yaşlanarak değil, yaşayarak tecrübe kazanılır. Zaman insanları değil, armutları olgunlaştırır". 
Can Yücel: "Toprak gibi olmalısın! Ezildikçe sertleşmelisin! Seni ezenler sana muhtaç kalmalı! Hayatı sende bulmalı."
Cevapla

Konuyu Paylaş : facebook gplus twitter



Konu ile Alakalı Benzer Konular
Konular Yazar Yorumlar Okunma Son Yorum
  PostgreSql Seri Oluşturma mad85 0 272 02-01-2018, Saat: 16:25
Son Yorum: mad85
  Trigger Oluşturma ve Oluşan Triggeri Tanımlama 3ddark 7 1.379 08-02-2017, Saat: 16:35
Son Yorum: esistem



Konuyu Okuyanlar: 1 Ziyaretçi