FB/IB'de SQLDialect'e göre alanların DataType tanımı nedir ?

Firebird ve Interbase veritabanları ve SQL komutlarıyla ilgli sorularınızı sorabilirsiniz. Delphi tarafındaki sorularınızı lütfen Programlama forumunda sorunuz.
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Bunun nedeni FB NUMERIC gibi float alanları tutarken temel tipler olan SMALLINT, INTEGER, INT64 gibi veri yapılarını kullanıyor. Yani 1,1 numeric için SMALLINT yetiyor ve içinde SMALLINT bir alanda bunu tutuyor. Yani NUMERIC, DECIMAL gibi alanlar aslında sanal alanlar.

Buna göre kodun Dialect 3 ve 1 için yeniden düzenlenmesi gerekecek.
Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4741
Kayıt: 09 Ara 2003 08:13
Konum: İstanbul
İletişim:

Mesaj gönderen mrmarman »

- Böylece adım adım tüm kodu açık hale getireceksin bak anladım... :lol: :lol: :lol:

- Tüm fonksiyonu yazayım... Ben sadece 8 ve 27 ile ilgilendiğimden kod karmaşasına girmemek için sadeleştirmiştim...

Kod: Tümünü seç

Function  TForm1.TipDetayi(Field_Type, Field_Sub_Type, Field_Length, Field_Precision, Field_Scale : Integer ) : String;
begin
  Result := '';
  Case Field_Type OF
    8 : // 'INTEGER';
        If IBDataBase1.SQLDialect = 3 then
        begin
          case Field_Sub_Type of
            0 : Result :=  'INTEGER';
            1 : Result :=  Format('NUMERIC (%d, %d)',[Field_Precision, Abs(Field_Scale)] );
            2 : Result :=  Format('DECIMAL (%d, %d)',[Field_Precision, Abs(Field_Scale)] );
          end; // Case
        end
        else // Dialect 3 değilse
        if Field_Scale <> 0 then
        begin
          If IBDataBase1.SQLDialect = 1
            then Result :=  Format('NUMERIC (%d, %d)',[9, Abs(Field_Scale)] ) // EMS, IBExpert, SQLHammer'den feyz alıyoruz Dial1 ise NUMERIC olsun
            else Result :=  Format('DECIMAL (%d, %d)',[9, Abs(Field_Scale)] );
        end
        else Result :=  'INTEGER';
    27: // 'DOUBLE';
        If Abs(Field_Scale) <> 0 then
        begin
          If IBDataBase1.SQLDialect = 1 // Yeni Dialect çıkarsa şimdiden uyumlu olduk :)))))
            then Result :=  Format('NUMERIC (%d, %d)',[15, Abs(Field_Scale)] )  // EMS, IBExpert, SQLHammer'den feyz alıyoruz Dial1 ise NUMERIC olsun
            else Result :=  Format('DECIMAL (%d, %d)',[15, Abs(Field_Scale)] );
        end
        else Result :=  'DOUBLE PRECISION';
    7 : // 'SMALLINT'
        If IBDataBase1.SQLDialect = 3 then
        begin
          case Field_Sub_Type of
            0 : Result :=  'SMALLINT';
            1 : Result :=  Format('NUMERIC (%d, %d)',[Field_Precision, Abs(Field_Scale)] );
            2 : Result :=  Format('DECIMAL (%d, %d)',[Field_Precision, Abs(Field_Scale)] );
          end; // Case
        end
        else // Dialect 3 değilse
        if Field_Scale <> 0
          then Result :=  Format('DECIMAL (%d, %d)',[4, Abs(Field_Scale)] )
          else Result :=  'SMALLINT';
    16: // 'INT64';
        If IBDataBase1.SQLDialect = 3 then
        case Field_Sub_Type of
          0 : Result :=  'DECIMAL (18, 0)';
          1 : Result :=  Format('NUMERIC (%d, %d)',[Field_Precision, Abs(Field_Scale)] );
          2 : Result :=  Format('DECIMAL (%d, %d)',[Field_Precision, Abs(Field_Scale)] );
        end;
    10: // 'FLOAT';
        Result :=  'FLOAT';
    14: // 'CHAR';
        Result :=  Format('CHAR (%d)',[Field_Length] );
    35: // 'TIMESTAMP';
        If IBDataBase1.SQLDialect = 3
          then Result :=  'TIMESTAMP'
          else Result :=  'DATE';
    13: // 'TIME';
        Result :=  'TIME';
    12: // 'DATE';
        Result :=  'DATE';
    37: // 'VARCHAR';
        Result :=  Format('VARCHAR (%d)',[Field_Length] );
    40: // 'CSTRING';
        Result :=  Format('CSTRING (%d)',[Field_Length] );
   261: // 'BLOB';
        Result :=  'BLOB';
     9: Result :=  'QUAD';
    11: Result :=  'D_FLOAT (Double Precision)';
  end; // Case
  Result := Format('%s /* (Tip:%d, SubType:%d) */',[Result, Field_Type, Field_Sub_Type] );
end;
Resim
Resim ....Resim
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Dialect 1 de DECIMAL varmış.

DECIMAL (1, 1) tanımlaması yapınca, TYPE = 8 SUB_TYPE = 2 ile ayrım yapılabiliyor.
Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4741
Kayıt: 09 Ara 2003 08:13
Konum: İstanbul
İletişim:

Mesaj gönderen mrmarman »

- Dialect 1 olduğuna emin misin ? Veritabanı mı oluşturup baktın ?

- IBase 6 Language Referans söyledğin şekilde tarif etmiş zaten. ilk mesajımda da yazmıştım. Ama Dialect 3 olduğunu düşünmüştüm...

Resim
Resim
Resim ....Resim
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Evet eminim. Dialect 1 de tablo yaratıp denedim. SQL ile bu bilgiyi almanın daha esnek olduğunu düşünerek bir SQL yazdım. İleride güncellemesi de kolay olur ve yükü server çeker. Henüz tamamlanmadı ama bir fikir olması açısından vereyim. Bu kod sadece Dialect 1 VT'lerin tiplerini almak için, dialect 3 e genişletilebilir ve optimize edilebilir:

Kod: Tümünü seç

/* Dialect 1 için tablo alanları bilgisi */
SELECT b.RDB$FIELD_NAME, c.RDB$FIELD_TYPE, c.RDB$FIELD_SUB_TYPE, b.RDB$FIELD_ID,
  c.RDB$FIELD_LENGTH, c.RDB$FIELD_SCALE,
case
  when c.RDB$FIELD_TYPE = 07 then /* SMALLINT */
    case
      when (c.RDB$FIELD_SUB_TYPE = 0 or c.RDB$FIELD_SUB_TYPE is null) then
        case when c.RDB$FIELD_SCALE = 0 then 'SMALLINT'
          else 'NUMERIC'
        end
      when c.RDB$FIELD_SUB_TYPE = 1 then 'NUMERIC'
      when c.RDB$FIELD_SUB_TYPE = 2 then 'DECIMAL'
    end
  when c.RDB$FIELD_TYPE = 08 then /* INTEGER */
    case
      when (c.RDB$FIELD_SUB_TYPE = 0 or c.RDB$FIELD_SUB_TYPE is null) then
        case when c.RDB$FIELD_SCALE = 0 then 'INTEGER'
          else 'NUMERIC'
        end
      when c.RDB$FIELD_SUB_TYPE = 1 then 'NUMERIC'
      when c.RDB$FIELD_SUB_TYPE = 2 then 'DECIMAL'
    end
  when c.RDB$FIELD_TYPE = 09 then 'QUAD'
  when c.RDB$FIELD_TYPE = 10 then 'FLOAT'
  when c.RDB$FIELD_TYPE = 11 then 'D_FLOAT'
  when c.RDB$FIELD_TYPE = 14 then 'CHAR'
  when c.RDB$FIELD_TYPE = 27 then /* DOUBLE PRECISION */
    case
      when (c.RDB$FIELD_SUB_TYPE = 0 or c.RDB$FIELD_SUB_TYPE is null) then
        case when c.RDB$FIELD_SCALE = 0 then 'DOUBLE PRECISION'
          else 'NUMERIC'
        end
      when c.RDB$FIELD_SUB_TYPE = 1 then 'NUMERIC'
      when c.RDB$FIELD_SUB_TYPE = 2 then 'DECIMAL'
    end
  when c.RDB$FIELD_TYPE = 35 then 'DATE'
  when c.RDB$FIELD_TYPE = 37 then 'VARCHAR'
  when c.RDB$FIELD_TYPE = 40 then 'CSTRING'
  when c.RDB$FIELD_TYPE = 261 then 'BLOB'
end
FROM RDB$RELATIONS a
INNER JOIN RDB$RELATION_FIELDS b
ON a.RDB$RELATION_NAME = b.RDB$RELATION_NAME
INNER JOIN RDB$FIELDS c
ON b.RDB$FIELD_SOURCE = c.RDB$FIELD_NAME
INNER JOIN RDB$TYPES d
ON c.RDB$FIELD_TYPE = d.RDB$TYPE
WHERE a.RDB$SYSTEM_FLAG = 0
AND d.RDB$FIELD_NAME = 'RDB$FIELD_TYPE'
ORDER BY b.RDB$FIELD_ID
-- Uyum problemi için yeniden düzenledim --
En son fduman tarafından 08 Haz 2005 05:12 tarihinde düzenlendi, toplamda 2 kere düzenlendi.
Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4741
Kayıt: 09 Ara 2003 08:13
Konum: İstanbul
İletişim:

Mesaj gönderen mrmarman »

Bu kodu sen mi yazdın. :) Bu yazdığın SQL dialect 1 içinse

Kod: Tümünü seç

  when c.RDB$FIELD_TYPE = 08 then 
    case 
      when (c.RDB$FIELD_SUB_TYPE = 0 or c.RDB$FIELD_SUB_TYPE is null) then 
        'INTEGER' 
      when c.RDB$FIELD_SUB_TYPE = 1 then 'NUMERIC' 
      when c.RDB$FIELD_SUB_TYPE = 2 then 'DECIMAL' 
    end 
Resim

Employee.GDB

SQLDialect 1
Type 8
SubType 0
Table : SALES
Field : TOTAL_VALUE

görünüyor ki, Bahsettiğim alan INTEGER çıkacak...
Resim
Resim ....Resim
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Evet ben yazdım. :)

Yalnız bir hata olmalı çünkü dialect 1 için NUMERIC 9,2 bir alan tanımlıyorum ve sub type = 1 görünüyor ve SQL'imin çalışması sonucunda hata oluşmuyor. Alan tipi düzgün geliyor.

Employee.GDB ye bir de ben bakayım.
Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4741
Kayıt: 09 Ara 2003 08:13
Konum: İstanbul
İletişim:

Mesaj gönderen mrmarman »

Sen de bir bakarsan iyi olur keza eğer dediğin gibi 1 çıkıyorsa buuuuuuuuuuuu kadar yazdımız şey boşa gidecek. Zaten Numeric görünen bir alan için bu kadar soru cevap yapıp vaktimizi çöpe atalım ki :lol: :oops:
Resim
Resim ....Resim
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Evet kontrol ettim. SQL'im doğru çalışıyor ve alan isimleri ve tipleri IB Expert ile birebir tutuyor. Sadece Employee tablosu dialect 3 olduğu için ve benim SQL henüz tam anlamıyla dialect 3 desteklemediği için INT64 gibi alan tiplerinin isimleri null olarak geliyor.

İstersen bir de sen kontrol et.
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Şimdi baktım da sen Employee tablosunu dialect 1 olarak açmışsın. Bendeki tablo dialect 3 olarak gayet düzgün görüntüleniyor.
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Employee tablosunda bir anormallik var.

Dialect 3 için:
SALES AGED alanı tip 16, subtype 0, scale -9 ve IBExpert bunu NUMERIC olarak tanıyor. Bu alan NUMERIC (18, 9) tipinde.

IBExpert ile aynı tipte bir alan yarattığımda :
tip 16, subtype 1, scale -9. IBExpert bunu da NUMERIC tanımlıyor. Zannedersem IB/FB 'ün önceki sürümlerinden gelen bir uyum problemi mevcut veya backup restore aracı ile bu tablo IB 6 dan FB 1.5 e aktarılırken bir hata yapmış. Ancak IBExpert bu hatayı kendi içinde scale kontrolü yaparak düzeltiyor.
Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4741
Kayıt: 09 Ara 2003 08:13
Konum: İstanbul
İletişim:

Mesaj gönderen mrmarman »

- Bir veritabanının IBDataBase.SQLDialect'ini açıkken set edemiyoruz galiba.

- SQLDialect 1 olan veritabanını 3 larak açmak nasıl yapılıyor ?
Resim
Resim ....Resim
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Sanırım Dialect 1 yaratıldığında Dialect 3 olarak açamıyordun. Tip uyuşmazlığı söz konusu olduğundan herhalde.

Dialect 3 için yazdığım SQL aşağıda. Bu da Dialect 1 de hatalı sonuç verir. Dialect 1 için yukardakini 3 için bunu kullanmalısınız.

Kod: Tümünü seç

/* Dialect 3 için tablo alanları bilgisi */
SELECT b.RDB$FIELD_NAME, c.RDB$FIELD_TYPE, c.RDB$FIELD_SUB_TYPE, b.RDB$FIELD_ID,
  c.RDB$FIELD_LENGTH, c.RDB$FIELD_SCALE,
case
  when c.RDB$FIELD_TYPE = 07 then  /* SMALLINT */
    case
      when (c.RDB$FIELD_SUB_TYPE = 0 or c.RDB$FIELD_SUB_TYPE is null) then
        case when c.RDB$FIELD_SCALE = 0 then 'SMALLINT'
          else 'NUMERIC'
        end
      when c.RDB$FIELD_SUB_TYPE = 1 then 'NUMERIC'
      when c.RDB$FIELD_SUB_TYPE = 2 then 'DECIMAL'
    end
  when c.RDB$FIELD_TYPE = 08 then /* INTEGER */
    case
      when (c.RDB$FIELD_SUB_TYPE = 0 or c.RDB$FIELD_SUB_TYPE is null) then
        case when c.RDB$FIELD_SCALE = 0 then 'INTEGER'
          else 'NUMERIC'
        end
      when c.RDB$FIELD_SUB_TYPE = 1 then 'NUMERIC'
      when c.RDB$FIELD_SUB_TYPE = 2 then 'DECIMAL'
    end
  when c.RDB$FIELD_TYPE = 09 then 'QUAD'
  when c.RDB$FIELD_TYPE = 10 then 'FLOAT'
  when c.RDB$FIELD_TYPE = 11 then 'D_FLOAT'
  when c.RDB$FIELD_TYPE = 12 then 'DATE'
  when c.RDB$FIELD_TYPE = 13 then 'TIME'
  when c.RDB$FIELD_TYPE = 14 then 'CHAR'
  when c.RDB$FIELD_TYPE = 16 then   /* INT64 */
    case
      when (c.RDB$FIELD_SUB_TYPE = 0 or c.RDB$FIELD_SUB_TYPE is null) then
        case when c.RDB$FIELD_SCALE = 0 then 'INT64'
          else 'NUMERIC'
        end
      when c.RDB$FIELD_SUB_TYPE = 1 then 'NUMERIC'
      when c.RDB$FIELD_SUB_TYPE = 2 then 'DECIMAL'
    end
  when c.RDB$FIELD_TYPE = 27 then  /* DOUBLE PRECISION */
    case
      when (c.RDB$FIELD_SUB_TYPE = 0 or c.RDB$FIELD_SUB_TYPE is null) then
        case when c.RDB$FIELD_SCALE = 0 then 'DOUBLE PRECISION'
          else 'NUMERIC'
        end
      when c.RDB$FIELD_SUB_TYPE = 1 then 'NUMERIC'
      when c.RDB$FIELD_SUB_TYPE = 2 then 'DECIMAL'
    end
  when c.RDB$FIELD_TYPE = 35 then 'TIMESTAMP'
  when c.RDB$FIELD_TYPE = 37 then 'VARCHAR'
  when c.RDB$FIELD_TYPE = 40 then 'CSTRING'
  when c.RDB$FIELD_TYPE = 261 then 'BLOB'
end
FROM RDB$RELATIONS a
INNER JOIN RDB$RELATION_FIELDS b
ON a.RDB$RELATION_NAME = b.RDB$RELATION_NAME
INNER JOIN RDB$FIELDS c
ON b.RDB$FIELD_SOURCE = c.RDB$FIELD_NAME
INNER JOIN RDB$TYPES d
ON c.RDB$FIELD_TYPE = d.RDB$TYPE
WHERE a.RDB$SYSTEM_FLAG = 0
AND d.RDB$FIELD_NAME = 'RDB$FIELD_TYPE'
ORDER BY a.RDB$RELATION_NAME, b.RDB$FIELD_ID
-- Yukarıda bahsettiğim uyum sorunu için yeniden düzenledim --
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

SQL kodlarını uyum sorunlarını kaldırmak için yeniden düzenledim. Doğru çalışıyor gibi görünüyor.
Kullanıcı avatarı
kefukar
Üye
Mesajlar: 705
Kayıt: 22 Kas 2004 03:08
İletişim:

Mesaj gönderen kefukar »

Üstadlar araya girdiğim için özür dilerim. Tam olarak olaya vakıf değilim ama çook faydalı şeylerden bahsettiğiniz aşikar. Allah razı olsun. Lakin bu konu Makaleler kısmına daha münasip değil mi? Hem burada kayboladabilir.. :oops:
Cevapla