Firebird tablo yapisini kod ile guncelleme

Yazdığınız makaleleri ve üyelerimizin işine yarayacağını düşündüğünüz kodlarınızı gönderebilirsiniz. Bu foruma soru sormayın!
Cevapla
Kullanıcı avatarı
sadettinpolat
Moderator
Mesajlar: 2131
Kayıt: 07 Ara 2003 02:51
Konum: Ankara
İletişim:

Firebird tablo yapisini kod ile guncelleme

Mesaj gönderen sadettinpolat »

Veritabaninin yapisinin gun gectikce degismesi ve bu degisiklikleri verileri bozmadan uygulamak programcilar icin kacinilmaz bir son. Ben isleri biraz kolaylastirmak icin veritabanindaki bazi alanlarin varolup olmadigi kontrol eden ve kontrol sonucunda eksik DDL kodlarini dosyalardan okuyup calistirann ufak bir sinif yazdim. oldukca ise yarar birsey. Tabi henuz bir cok eksigi mevcut. Ben mevcut hali ile buraya koyuyorum , ekleme yapmak isteyenler burdan devam ederse daha iyi olur kanaatindeyim.

firebirdUtils.pas

Kod: Tümünü seç

{*
  Veritabani uzerinde yapilan degisiklikleri
  script dosyalari vasitasiyla otomatik hale getirmek icin
  kullanilan siniflarin yeraldigi unittir.

  @Author Sadettin POLAT
  @Version 09 Subat 2007 1.3
}

unit dbUtils;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,IBQuery, StdCtrls,
  dateutils,IBDatabase,IBSQL,
  strutils, ib,ibscript;


{*
  script dosyalarinin yer aldigi dizin.
}
const cntDDLPath='dbUpdates\'; /// script dosyalarinin yer aldigi dizin.

type

{*
  Yapilan veritabani degisikliklerini script dosyasindan okuyarak
  bagli bulundugu veritabanina uygulayan siniftir.

  yeni bir tablo , domain , field eklenecegi zaman oncelikle
  sinifin varolan metodlari kullanilarak ilgili nesnenin
  daha onceden veritanina eklenip eklenmedigi belirlenir
  eger eklenmemisse uygun script dosyasi belirtilerek
  nesnenin veritabanina eklenmesi saglanir...
}

  TFirebirdUtils = class
  strict private
  FDB:TIBDatabase;  /// guncellemenin yapilacagi veritabani
  FIBQuery:TIBQuery;  ///guncelleme yapmadan once ilgili nesnelerin veritabaninda olup olmadigini sorgulamak icin kullanilan bilesen
  FIBScript:TIBScript; ///script dosyalarini calistiran nesne
  FTableDDL: TStrings; ///buna gerek yok. bunun icin FIBScript.script kullanilacak
  procedure SetTableDDL(const Value: TStrings); ///FIBScript.scriptten sonra buna da gerek kalmadi
  procedure ShowError(aCustomErrorMessage:String;aException:Exception); ///islemler sirasinda meydana gelen hatalari isleyen ve kullaniciya gosteren metod
  published
    { Private declarations }
  public
  constructor Create(aDB:TIBDatabase);
  destructor Destroy;override;
  procedure ExecuteScript(aScriptFile:String);
  function isDomainExist(aDomainName:String):Boolean;
  function isTableExist(aTableName:string):Boolean;
  function isFieldExist(aTableName,aFieldName:string):Boolean;
  function isIndexExist(aIndexName:String):Boolean;
//zaten isIndexAlready adli bu isi yapan bir fonksiyon varmis :) neyse fazla mal göz cikarmaz ehehehe
  function isFieldTypeOld(aTableName,aFieldName,aNewFieldType:string):Boolean;
  function isIndexUnique(aTableName:string;aIndexName:string):Boolean;
  function isIndexAlready(aTableName:string;aIndexName:string):Boolean;
  function getIndexFieldCount(aIndexName:String):Byte;
  property TableDDL:TStrings read FTableDDL write SetTableDDL;
    { Public declarations }
  end;

implementation



{ TDBTable }

{*
  dbTable nesnesinin calisabilmesi icin gerekli olan
  ilk islemlerin yapilmasindan sorumlu olan metod.
  Script dosyalarini calistiracak olan IBScript ve
  nesnelerin varolup olmadigini kontrol etmek icin
  IBQuery burda olusturulur...

  @param  aDB degisikliklerin uygulanacagi veritabani
  @author     Sadettin POLAT
  @version    1.1
}

constructor TFirebirdUtils.Create(aDB: TIBDatabase);
begin
FDB :=aDB;
FTableDDL :=TStringList.Create; //fibscript.script ozelligi oldugu icin buna artik gerek yok...

FIBQuery :=TIBQuery.Create(nil);
FIBQuery.Database :=FDB;
FIBQuery.Transaction :=FDB.DefaultTransaction;

FIBScript := TIBScript.Create(nil);
FIBScript.Database :=FDB;
FIBScript.Transaction :=FDB.DefaultTransaction;

end;


{*
  dbTable nesnesi calismasini bitirdikten sonra
  Create meotunda olusturulan nesneler burda yok edilir.

  @author     Sadettin POLAT
  @version    1.1
}

destructor TFirebirdUtils.Destroy;
begin
  FreeAndNil(FTableDDL);
  FreeAndNil(FIBQuery);
  FreeAndNil(FIBScript);
  inherited;
end;


{*
  Script dosyasini cntDDLPath adresinden IBScript
  nesnesine yukleyerek calistiran metod.

  @param  aScriptFile Scriptin yer aldigi dosyanin adi
  @author     Sadettin POLAT
  @version    1.1
}


procedure TFirebirdUtils.ExecuteScript(aScriptFile: String);
begin
if FileExists(cntDDLPath+aScriptFile) = false  then Exit;
TableDDL.Clear;
TableDDL.LoadFromFile(cntDDLPath+aScriptFile);
if trim(TableDDL.Text)=''  then  exit;
   //raise Exception.Create('DDL ifadesi girilmemiş...');
FIBScript.Script := TableDDL;
if FIBScript.ValidateScript = false then
   raise Exception.Create('Hatalı Script(' + aScriptFile+')');
try
    FIBScript.ExecuteScript;
except
  on e:Exception do
  begin
    FIBScript.Transaction.RollbackRetaining;
    ShowError(aScriptFile + ' scripti çalışırken hatalar oluştu',e);
    exit;
    end;
  end;
  FIBScript.Transaction.CommitRetaining;
  ShowMessage(aScriptFile +' adlı script basarili bir sekilde calistirildi...');
end;

{*
  Parametre olarak verilen indexin kac tane alan uzerinde
  olusturulmus oldugunu geriye donderir.
  A indexi b,c fieldlerinin birlesiminden olusan bir index ise
  geriye 2 degerini donderir...

  @param  aIndexName Field sayisi bulunacak olan index adi
  @return Indexin kac tane field uzerinde olusturuldugunu geri donderir.
  @author     Sadettin POLAT
  @version    1.1
}


function TFirebirdUtils.getIndexFieldCount(aIndexName: String): Byte;
begin
{
select count(*) from rdb$index_segments r
where r.rdb$index_name = 'TABLO_IDX2'

dikkat !!! RDB$INDICES tablosundaki RDB$SEGMENT_COUNT alanindan da bulunabilirdi...

}
FIBQuery.SQL.Clear;
FIBQuery.SQL.Add('select count(*) from rdb$index_segments r');
FIBQuery.SQL.Add('where r.rdb$index_name = :PRM_INDEXNAME');
FIBQuery.Params[0].AsString :=aIndexName;
FIBQuery.Open;
Result := FIBQuery.Fields[0].AsInteger;
end;

{*
  Bir domainin veritabaninda olup olmadigini kontrol eder.


  @param  aDomainName Kontrol edilecek domain adi
  @return Domain veritabaninda varsa True yoksa False degeri alir.
  @author     Sadettin POLAT
  @version    1.1
}

function TFirebirdUtils.isDomainExist(aDomainName: String): Boolean;
begin
FIBQuery.SQL.Clear;
FIBQuery.SQL.Add('select * from rdb$fields r');
FIBQuery.SQL.Add('where r.rdb$system_flag = 0');
FIBQuery.SQL.Add('and r.rdb$field_name = :PRM_DOMAINNAME');
FIBQuery.Params[0].AsString :=aDomainName;
FIBQuery.Open;
Result := FIBQuery.Fields[0].IsNull=False;
end;

{*
  Bir tablonun belirtilen field alanina sahip olup olmadigini kontrol eder.
  Fieldin tipi bu metotda kontrol edilmez !!!

  @param  aTableName Fieldin yer aldigi tablo adi
  @param aFieldName Kontrol edilecek field adi
  @return Belirtilen field belirtilen tabloda varsa true yoksa false degeri alir
  @author     Sadettin POLAT
  @version    1.1
}


function TFirebirdUtils.isFieldExist(aTableName, aFieldName: string): Boolean;
begin
FIBQuery.SQL.Clear;
FIBQuery.SQL.Add('select * from rdb$relation_fields db');
FIBQuery.SQL.Add('where db.rdb$field_name =:PRM_FIELD');
FIBQuery.SQL.Add('and db.rdb$relation_name =:PRM_TABLENAME');
FIBQuery.Params[0].AsString :=aFieldName;
FIBQuery.Params[1].AsString :=aTableName;
FIBQuery.Open;
Result := FIBQuery.Fields[0].IsNull=False;
end;


{*
  Fieldin tipinin belirtilen tipte olup olmadigini kontrol eder.

  @param  aTableName fieldin yer aldigi tablo adidir.
  @param aFieldName tipi kontrol edilecek fieldin adidir
  @param aNewFieldType fieldin olmasi gereken yeni tip degeridir.
  @return Fieldin tipi eski ise true belirtilen tipi sahipse false donderir.
  @author     Sadettin POLAT
  @version    1.1
}

function TFirebirdUtils.isFieldTypeOld(aTableName, aFieldName,
  aNewFieldType: string): Boolean;
begin
FIBQuery.Close;
FIBQuery.SQL.Clear;
FIBQuery.SQL.Add('select RDB$FIELD_SOURCE from rdb$relation_fields db');
FIBQuery.SQL.Add('where db.rdb$field_name = :PRM_FIELDNAME');
FIBQuery.SQL.Add('and db.rdb$relation_name =:PRM_TABLENAME');
FIBQuery.Params[0].AsString :=aFieldName;
FIBQuery.Params[1].AsString :=aTableName;
FIBQuery.Open;
Result := not (Trim(FIBQuery.Fields[0].AsString) = aNewFieldType);
end;

function TFirebirdUtils.isIndexUnique(aTableName:string;aIndexName:string):Boolean;
begin
{
SELECT RDB$INDEX_NAME
  FROM RDB$INDICES
 WHERE RDB$RELATION_NAME='TABLO'
   AND RDB$INDEX_NAME = 'TABLO_IDX1'
   AND RDB$UNIQUE_FLAG = 1;
}
   FIBQuery.Close;
   FIBQuery.SQL.Clear;
   FIBQuery.SQL.Add('SELECT RDB$INDEX_NAME');
   FIBQuery.SQL.Add('FROM RDB$INDICES');
   FIBQuery.SQL.Add('WHERE RDB$RELATION_NAME=:PRM_TABLENAME');
   FIBQuery.SQL.Add('AND RDB$INDEX_NAME = :PRM_INDEXNAME');
   FIBQuery.SQL.Add('AND RDB$UNIQUE_FLAG = 1');
   FIBQuery.Params[0].AsString := aTableName;
   FIBQuery.Params[1].AsString := aIndexName;
   FIBQuery.Open;
   Result := FIBQuery.Fields[0].IsNull=False;
end;

function TFirebirdUtils.isIndexAlready(aTableName:string;aIndexName:string):Boolean;
begin
   FIBQuery.Close;
   FIBQuery.SQL.Clear;
   FIBQuery.SQL.Add('SELECT RDB$INDEX_NAME');
   FIBQuery.SQL.Add('FROM RDB$INDICES');
   FIBQuery.SQL.Add('WHERE RDB$RELATION_NAME=:PRM_TABLENAME');
   FIBQuery.SQL.Add('AND RDB$INDEX_NAME = :PRM_INDEXNAME');
   FIBQuery.Params[0].AsString := aTableName;
   FIBQuery.Params[1].AsString := aIndexName;
   FIBQuery.Open;
   Result := FIBQuery.Fields[0].IsNull=False;
end;



{*
  Belirtilen indexin varolup olmadigini kontrol eder.


  @param  aIndexName Kontrol edilecek indexin adi
  @return Belirtilen index var ise true yoksa false donderilir.
  @author     Sadettin POLAT
  @version    1.1
}

function TFirebirdUtils.isIndexExist(aIndexName: String): Boolean;
begin
{
select count(*) from RDB$INDICES r
where r.rdb$index_name ='TABLO_IDX1'
}
FIBQuery.SQL.Clear;
FIBQuery.SQL.Add('select count(*) from RDB$INDICES r');
FIBQuery.SQL.Add('where r.rdb$index_name =:PRM_INDEXNAME');
FIBQuery.Params[0].AsString :=aIndexName;
FIBQuery.Open;
Result := FIBQuery.Fields[0].AsInteger=1;
end;

{*
  fibscript bileseninden sonra artik TableDDL ozelligine gerek
  kalmadigindan siniftan ihrac edilecek ozelliklerden birisi...

  @param  Value ddl kodlari
  @author     Sadettin POLAT
  @version    1.1
}

procedure TFirebirdUtils.SetTableDDL(const Value: TStrings);
begin
  FTableDDL := Value;
end;

{*
  Script Execute sirasinda meydana gelen hatalari kullaniciya gosteren metod

  @param  aCustomErrorMessage Kullaniciya verilmek istenen herhangi bir mesaj
  @param aException olusan istisnanin ShowError tarafindan islenebilmesi icin kullanilan degisken
  @param aNewFieldType fieldin olmasi gereken yeni tip degeridir.
  @author     Sadettin POLAT
  @version    1.1
}

procedure TFirebirdUtils.ShowError(aCustomErrorMessage: String;
  aException: Exception);
begin
  if aException.ClassNameIs('EIBInterbaseError') then
  begin
    MessageDlg(Format('Mesaj: %s ' + #13+#13+
                      'IBErrorCode: %d - SQLErrorCode: %d',
                      [aCustomErrorMessage,
                      EIBInterbaseError(aException).IBErrorCode,
                      EIBInterbaseError(aException).SQLCode])+#13+
                      'Message: '+aException.Message,mterror,[mbok],0);
  end
  else
  begin
    MessageDlg('Yapılan İşlem Sırasında Hata Oluştu!' +aCustomErrorMessage+ #13 + #13+
               'Hata : ' + aException.Message + #13 +
               'Hata Kodu : ' + aException.ClassName,mterror,[mbok],0);
  end;
end;



{*
  Tablonun veritabaninda varolup olmadigini kontrol eder.

  @param  aTableName kontrol edilecek tablonun adi
  @return tablo varsa true yoksa false donderir
  @author     Sadettin POLAT
  @version    1.1
}
function TFirebirdUtils.isTableExist(aTableName: string): Boolean;
begin
FIBQuery.Close;
FIBQuery.SQL.Clear;
FIBQuery.SQL.Add('SELECT COUNT(RDB$RELATION_NAME)');
FIBQuery.SQL.Add('FROM RDB$RELATIONS');
FIBQuery.SQL.Add('WHERE RDB$RELATION_NAME = :PRM_TABLOADI');
FIBQuery.SQL.Add('AND  RDB$VIEW_SOURCE IS NULL');

FIBQuery.Params[0].AsString :=aTableName;
FIBQuery.Open;
Result := FIBQuery.Fields[0].AsInteger > 0;
end;

end.
kullanimi

Kod: Tümünü seç

procedure TForm3.Button1Click(Sender: TObject);
var
FBUtils:TFirebirdUtils;
begin

FBUtils :=TFirebirdUtils.Create(IBDatabase1);
//belirtilen tablo yoksa tabloyu olusturmak icin gerekli
//olan sql kodlarini dosyadan calistirir.
if FBUtils.isTableExist('TabloAdi') = false then
   FBUtils.ExecuteScript('TabloDDLininYerAldigiDosya.sql');

//belirtilen tabloda belirtilen alan yoksa ilgili alani
// olusturmak icin gerekli olan sql kodlarini
//dosyadan calistirir.
if FBUtils.isFieldExist('TabloAdi','FieldAdi') = False then
  FBUtils.ExecuteScript('FieldDDLininYerAldigiDosya.sql');

FreeAndNil(FBUtils);
end;

"Sevmek, ne zaman vazgececegini bilmektir." dedi, bana.

---
http://sadettinpolat.blogspot.com/
Kullanıcı avatarı
sabanakman
Kıdemli Üye
Mesajlar: 3081
Kayıt: 17 Nis 2006 08:11
Konum: Ah bi Antalya olaydı keşke (Ankara)

Re: Firebird tablo yapisini kod ile guncelleme

Mesaj gönderen sabanakman »

sadettinpolat yazdı:...Tabi henuz bir cok eksigi mevcut. Ben mevcut hali ile buraya koyuyorum , ekleme yapmak isteyenler burdan devam ederse daha iyi olur kanaatindeyim...
Bu alan değişikliği güncellemeleri göründüğünden daha zahmetli bir meseleymiş. Bunu da SQL Server için çalışırken anladım. Öğrenmeye ihtiyaç duyduğum çok fazla bir konu kalmamasına karşın bir yıldır tamamlamaya fırsat bulamadığımdan durumu kavramış bulunmaktayım :N) . O yüzden bu kodlar tam ihtiyaç karşılayamadığı durumda bile kişi yine ihtiyaç duyduğu yerlere bu kodlardan ilham alarak açığı kapatacaktır.
Şaban Şahin AKMAN
_________________
Derin olan kuyu değil kısa olan iptir. - .
Cevapla