FireBird UDF uygulamasında STRING Problemi ...

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Cevapla
delphi_programmer
Üye
Mesajlar: 53
Kayıt: 01 Haz 2005 11:47

FireBird UDF uygulamasında STRING Problemi ...

Mesaj gönderen delphi_programmer »

Bu soruyu makaleler kısmında Sayın FAOSoft'un değerli makalesine cevap olarak sormuştum ancak sanırım sormam gereken yer orası değil burasıymış.

Kendisinin makalesi şuradadır :

viewtopic.php?p=55517


Sayın FAOSoft,

Bu değerli bilgileri verdiğiniz için öncelikle size teşekkür etmek istiyorum.
Gerçi siz bu bilgileri 2004'te vermişsiniz ama benim bugün işime yaradı.

Ancak bir yerde takıldım ve bu konuda sizden yardım alabileceğimi düşünüyorum. Eminim takıldığım nokta küçük birşeydir ama ne yazık ki çözemedim henüz.

Müsaadenizle hemen anlatayım.

Bir UDF yapıyorum. Görevi mail göndermek. (Ancak sorunum mail gönderme işlemleriyle alakalı değil tabii)

Delphi PROJECT kodum bu şekilde :

Kod: Tümünü seç

library Project1;

uses
  Unit1 in 'Unit1.pas';

exports

  mail_gonder;

begin
end.
Delphi UNIT kodum ise bu şekilde :

Kod: Tümünü seç

unit Unit1;

interface

uses ib_util,idsmtp,idmessage,forms;

function mail_gonder(var bilgi:pchar):pchar;stdcall;

implementation

function mail_gonder(var bilgi:pchar):pchar;
var
IdMsgSend:TIdMessage;
SMTP:TidSMTP;
begin
  IdMsgSend:=TIdMessage.Create(application);
  SMTP:=TidSMTP.Create(Application);
  with IdMsgSend do
      begin
         Body.Add(bilgi);
         From.Text := 'deneme';
         ReplyTo.EMailAddresses := 'test@test.com';
         Recipients.EMailAddresses := 'test@test.com';
         Subject := 'BASLIK';
         Priority := TIdMessagePriority(0); { Message Priority }
      end;

   SMTP.AuthenticationType := atLogin;
   SMTP.Username:='Test_Kullanicisi';
   SMTP.Password:='Test_Kullanici_Sifresi';

   {General setup}
   SMTP.Host := '10.10.1.8';
   SMTP.Port := 25;

   {now we send the message}
   SMTP.Connect;
   try
      SMTP.Send(IdMsgSend);
   finally
      SMTP.Disconnect;
      Result:='geriye_donus_degeri_onemli_degil';
   end;
   IdMsgSend.Free;
   SMTP.Free;
end;


end.
FireBird'de UDF oluşturmak için kullandığım kod ise şu şekilde :

Kod: Tümünü seç

DECLARE EXTERNAL FUNCTION F_MAIL_GONDER
    cstring(300)
RETURNS cstring FREE_IT
ENTRY_POINT 'mail_gonder' MODULE_NAME 'project1.dll'


Evet gördüğünüz gibi bu fonksiyonun dönüş değeri önemli değil.
Ve bir BILGI isminde bir parametre alıyor ve bunu unit içinde kullanıyor.

Ancak BILGI isimli değişkeni kullandığım zaman FireBird'de database bağlantısı kopuyor. (bir memory problemi oluşuyor anladığım kadarı ile)

Bunu biraz açıklayayım :
Örneğin şu anda UNIT kodu içinde

Kod: Tümünü seç

Body.Add(bilgi);
satırı var ve bu yüzden hata veriyor.

Ancak BILGI değişkenini UNIT içinde kullanmazsam problem yok. DLL dosyam işini yapıyor ve maili de gönderiyor ama tabii ki değişkenleri kullanmaz isek yapıyor bunu.

Örneğin

Kod: Tümünü seç

Body.Add("test");
şeklinde kullanırsam hata vermiyor.

Şimdi benim problemimin "UDF - Delphi - String" problemi olduğunu zannediyorum.

Gördüğünüz gibi değişkenim PCHAR olarak tanımlı.
Aynı zamanda ib_util uses'a eklenmiş durumda ve dll ve pas dosyaları da projemin olduğu klasörde bulunuyor.

Sizce String işlemlerinin neresinde hata yapıyorum ?

Cevabınız için şimdiden teşekkürler.
Kullanıcı avatarı
sadettinpolat
Moderator
Mesajlar: 2131
Kayıt: 07 Ara 2003 02:51
Konum: Ankara
İletişim:

Mesaj gönderen sadettinpolat »

Kod: Tümünü seç

function mail_gonder(var bilgi:pchar):pchar;stdcall;
satırını

Kod: Tümünü seç

function mail_gonder(const bilgi:pchar):pchar;stdcall;
olarak degistirip deneyin. degiskeni var parametresiyle gectiginizden olabilir.
"Sevmek, ne zaman vazgececegini bilmektir." dedi, bana.

---
http://sadettinpolat.blogspot.com/
delphi_programmer
Üye
Mesajlar: 53
Kayıt: 01 Haz 2005 11:47

Mesaj gönderen delphi_programmer »

Sadettin bey ilginiz için teşekkürler.

Az önce const ile denedim. Tek bir değişken aldığında sorun olmuyor. Tam problemi çözdüm diyordum ki

Ancak şimdi FireBird'den DLL'e gönderdiğim parametre sayısını yükseltmeyi denedim. Çünkü bir kaç tane parametre göndermem gerekiyor.

Kod: Tümünü seç

function mail_gonder(const bilgi1,bilgi2,bilgi3,bilgi4,bilgi5:pchar):pchar;stdcall;
şeklinde deniyorum. (10 tane değişkenim var)

DLL üzerine düşeni yapıyor ve maili de gönderiyor.
Ancak dll'i çalıştırdıktan sonra Stack Overflow hatası alıyorum.
Bir iki çalışmadan sonra da "database connection lost" oluyor ve database bağlantım kopuyor.

Nedeni ne olabilir?

Teşekkürler.
Kullanıcı avatarı
sadettinpolat
Moderator
Mesajlar: 2131
Kayıt: 07 Ara 2003 02:51
Konum: Ankara
İletişim:

Mesaj gönderen sadettinpolat »

http://sourceforge.net/projects/fireudflib/

burdaki udf de yanlis hatirlamiyorsam mail gonderme vardi.
burdakini kullanabilir veya kaynak koda bakarak nerde hata yaptigini bulabilirsin.
"Sevmek, ne zaman vazgececegini bilmektir." dedi, bana.

---
http://sadettinpolat.blogspot.com/
delphi_programmer
Üye
Mesajlar: 53
Kayıt: 01 Haz 2005 11:47

Mesaj gönderen delphi_programmer »

Benim problemim mail gönderememek değil ki zaten mail gönderebiliyorum. Sadece değişkenleri atayamıyorum.
Yine de teşekkür ediyorum ve konunun çözümü hakkında gelebilecek cevapları merakla bekliyorum :)
Kullanıcı avatarı
Opt2000
Üye
Mesajlar: 216
Kayıt: 09 Tem 2003 10:04

Mesaj gönderen Opt2000 »

Selam,

Sorununuzun asıl sebebi calling convertion yanlışlığı. Siz fonksiyonunuzu stdcall ile tanımlamışsınız, ama Firebird cdecl kulanıyor. Bu iki yöntem arasındaki fark genelde parametrelerin bellek sıralaması ve bellekteki konumları ile ilgilidir. Bu yüzden de parametre kullanmaya çalıştığınız zaman bellek hataları alıyorsunuz.

stdcall'u cdecl'e çevirdikten sonra sorun kalmayacaktır.

Kolay gelsin,
Bahadır Alkaç
delphi_programmer
Üye
Mesajlar: 53
Kayıt: 01 Haz 2005 11:47

Mesaj gönderen delphi_programmer »

Opt2000 yazdı:Selam,

Sorununuzun asıl sebebi calling convertion yanlışlığı. Siz fonksiyonunuzu stdcall ile tanımlamışsınız, ama Firebird cdecl kulanıyor. Bu iki yöntem arasındaki fark genelde parametrelerin bellek sıralaması ve bellekteki konumları ile ilgilidir. Bu yüzden de parametre kullanmaya çalıştığınız zaman bellek hataları alıyorsunuz.

stdcall'u cdecl'e çevirdikten sonra sorun kalmayacaktır.

Kolay gelsin,
Bahadır Alkaç
Sn. Opt2000,
standard çağrıyı cdecl çağırısı şeklinde değiştirince problemim çözüldü :)
Şimdi 10 tane değişken alabiliyor ve herhangi bir problem de yok.
1 haftadır "cdecl" yüzünden uğraştığıma inanamıyorum ama olsun, tecrübe tecrübedir. Teşekkürler.

Bu arada bu yaptığım fonksiyonu şimdi bir trigger yazarak orada çalışmasını sağlamak istiyorum.
Aşağıdaki şekilde bir trigger yazdım ancak "mail_gonder" fonksiyonu böyle mi çağırılmalı yoksa
"select mail_gonder('aa','bb','cc') from rdb$database" şeklinde mi yapmalıyım ?
Rica etsem bu koda bir göz atabilir misiniz ...

Yazdığım trigger kodu şu şekilde :

Kod: Tümünü seç

AS
begin

if (old.exitdate<>new.exitdate) then /* İşten çıkış tarihi değişmiş ise */ 
  begin
    mail_gonder'degisken1','degisken2','degisken3','degisken4','degisken5');
  end

end
Yeniden teşekkürler.
delphi_programmer
Üye
Mesajlar: 53
Kayıt: 01 Haz 2005 11:47

Mesaj gönderen delphi_programmer »

Arkadaşlar zamanı olan bir arkadaşım bu Trigger'ı bir kontrol edebilir mi ?
Kusura bakmayın acele ediyorum ama uygulamayı bitirmem icap ediyordu. Uzun zamandır String problemine takılı kaldığım için bitirme zamanımı oldukça aştım.

Sorun kısaca şu :
"mail_gonder" ismindeki UDF' imi Trigger içinde kullanmak istiyorum.

Şöyle denedim ama çalıştıramadım :

Kod: Tümünü seç

AS 
begin 

if (old.exitdate<>new.exitdate) then /* İşten çıkış tarihi değişmiş ise */ 
  begin 
    mail_gonder('degisken1','degisken2','degisken3','degisken4','degisken5'); 
  end 

end
Kullanıcı avatarı
Opt2000
Üye
Mesajlar: 216
Kayıt: 09 Tem 2003 10:04

Mesaj gönderen Opt2000 »

Selam,

Daha önce Firebird'le ilgilenmedim. Ayrıca VT programcılığım da iyi değildir. Bu yüzden yardım olamayacağım.

Kolay gelsin,
Bahadır Alkaç
Kullanıcı avatarı
rsimsek
Admin
Mesajlar: 4482
Kayıt: 10 Haz 2003 01:48
Konum: İstanbul

Mesaj gönderen rsimsek »

Fonksiyon bir sonuç döndürdüğüne göre şöyle bir kullanım daha uygun olabilir :wink:

Kod: Tümünü seç

AS 
declare Sonuc varchar(50);
begin
  Sonuc = '';
  if (old.exitdate<>new.exitdate) then /* İşten çıkış tarihi değişmiş ise */
    Sonuc = mail_gonder'degisken1','degisken2','degisken3','degisken4','degisken5');
end
Bilgiyi paylaşarak artıralım! Hayatı kolaylaştıralım!!
delphi_programmer
Üye
Mesajlar: 53
Kayıt: 01 Haz 2005 11:47

Mesaj gönderen delphi_programmer »

rsimsek hocam çok teşekkürler;
Ben de bu bir fonksiyon ve geri sonuç döndürüyor, bir değişkene atayayım dedim ve bu şekilde yaptım. Hatta değişken olarak da "sonuc" kullanmıştım.

Yeniden foruma döndüm ve şu şekilde çözdüm diyecektim ki siz cevap yazmışsınız, teşekkürler.

Bu arada bir küçük sorunum daha var. (Az kaldı bitecek :) )

Kod: Tümünü seç

AS
declare variable sonuc varchar(64);

begin
  /* Trigger text */
/*if (old.exitdate<>new.exitdate) then*/
/*  begin*/
sonuc=mail_gonder('mail_adresi@mail.com',old.PAYROLLEMPNO,old.name,(select COMPANYNAME from COMPANY WHERE COMPANYID=old.companyid),old.department,new.companyid,new.department,old.entrydate,new.exitdate,old.idno);
/*  end */

end
Benim üzerinde çalıştığım tablo üstünde bir COMPANYID bulunuyor.
Bu da COMPANY tablosundaki COMPANYNAME'i refere ediyor.

Yani ben Trigger içerisinde UDF'ime parametre gönderirken COMPANYID 'yi değil de COMPANYNAME ' i göndermek istiyorum.

Bunun için

mail_gonder('aaaa',(select companyname from company where companyid=old.companyid),'bbb','ccc');

gibi bir kod kullanmayı düşündüm ama kendi çapımda saçmalamış da olabilirim elbette.

Örneğin sirket_adi isimli bir değişkene bir select cümlesinden dönen değeri nasıl atayabilirim ve bunu UDF'e parametre olarak nasıl gönderebilirim ?

Çok teşekkürler, iyi çalışmalar ...
delphi_programmer
Üye
Mesajlar: 53
Kayıt: 01 Haz 2005 11:47

Mesaj gönderen delphi_programmer »

Selamlar problemi çözdüm.
Ben çektim Allah size çektirmesin diye Trigger'ı da buraya yazayım ki tam olsun :)

Kod: Tümünü seç

AS
declare variable sonuc varchar(200);
declare variable eski_firma varchar(200);
declare variable yeni_firma varchar(200);

declare variable eski_departman varchar(200);
declare variable yeni_departman varchar(200);

begin

SELECT companyname FROM company where companyid=old.companyid INTO :eski_firma;
SELECT description FROM departments where (department=old.department AND companyid=old.companyid) INTO :eski_departman;

SELECT companyname FROM company where companyid=new.companyid INTO :yeni_firma;
SELECT description FROM departments where (department=new.department AND companyid=new.companyid) INTO :yeni_departman;

  /* Trigger text */
/*if (old.exitdate<>new.exitdate) then*/
/*  begin*/
sonuc=mail_gonder('test@test.com',old.PAYROLLEMPNO,old.name,eski_firma,eski_departman,yeni_firma,yeni_departman,old.entrydate,new.exitdate,old.idno);
/*  end */

end

Bu örnek Trigger içinden alınan old_companyid gibi bir bilgiyi kullanarak diğer ilişkili tablodan company text'ini almayı örneklemiş oluyor.

Tüm ilgilinen kişilere teşekkürler.
Kullanıcı avatarı
rsimsek
Admin
Mesajlar: 4482
Kayıt: 10 Haz 2003 01:48
Konum: İstanbul

Mesaj gönderen rsimsek »

delphi_programmer yazdı:...
mail_gonder('aaaa',(select companyname from company where companyid=old.companyid),'bbb','ccc');
...
Yerine doğrusu;

Kod: Tümünü seç

--...
declare dlr_campany_name varchar(50);
begin
  select companyname from company where companyid=old.companyid into :dlr_campany_name;
  mail_gonder('aaaa',dlr_campany_name,'bbb','ccc');
--...
end;
şeklinde olacak :wink:
Bilgiyi paylaşarak artıralım! Hayatı kolaylaştıralım!!
delphi_programmer
Üye
Mesajlar: 53
Kayıt: 01 Haz 2005 11:47

Mesaj gönderen delphi_programmer »

rsimsek hoca teşekkürler, yukarıda da belirttiğim gibi ben de o şekilde yapmıştım, mükemmel çalışıyor :)

Ama takıldığı küçücük, minnacık bi kodu daha var :)

Kod: Tümünü seç

if ((old.exitdate<>new.exitdate) OR (old.department<>new.department) OR (old.subdepartment<>new.subdepartment))  then
  begin
sonuc=gonder(new.PAYROLLEMPNO,new.name,eski_firma,eski_departman,yeni_firma,yeni_departman,old.exitdate,new.exitdate,eski_bolum,yeni_bolum);
  end

Yukarıdaki IF cümlesinde yapmak istediğim,
"EXITDATE değişirse ya da DEPARTMAN değişirse ya da SUBDEPARTMAN değişirse" mail göndermek.

Ancak
Eğer EXITDATE NULL ise ve EXITDATE değiştirilmiş ise IF cümlesi çalışmıyor.

Yani eski değeri NULL iken yeni değer yazıldıysa IF çalışmıyor.
Ancak eski değeri örneğin 11.11.2007 ve yeni değeri 12.12.2007 ise çalışıyor.

Bu kadar karışık anlatılabilirdi zaten, umarım anlatabilmişimdir.

Teşekkürler.
delphi_programmer
Üye
Mesajlar: 53
Kayıt: 01 Haz 2005 11:47

Mesaj gönderen delphi_programmer »

Kod: Tümünü seç

if (((old.exitdate is NULL) AND (new.exitdate is not NULL)) OR ....
şeklinde yazınca oldu :)
Cevapla