OCI-Lob  sınıfını tanımıştık. bu sınıfın insert ve update  sorguları için kullanılan metodu olan OCI-Lob::save()  metodunu inceliyor olacağız.  Update sorgularımız için şartımıza uyan bir satır  yoksa php OCI_INVALID_HANDLE gibi bir hata fırlatıyor. update işlemlerini bir sonraki yazıda işleyeceğimiz için şimdilik sadece bahsedip geçiyoruz.

OCI-Lob
bool save ( string $data [, int $offset ] )

save metodu LOB alanlara veri yazmak için kullanılır. OCI lob objelerinin indikasyon özelliği olduğundan  opsiyonel olarak  offset değeri de verebiliyoruz . yani istersek veriyi  lobun istediğimiz alanına yazabiliyoruz.

işte örnek insert işlemi.

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
$conn=oci_connect(); // bağlantı ayarlarınız
 
$sql = "INSERT INTO loblar
          (
            id,
            lobalan
          )
       VALUES
          (
            loblar_seq.NEXTVAL,
            -- Boş bir CLOB oluşturuyoruz
            EMPTY_CLOB()
          )
       RETURNING
          -- Lob locator dönderiyoruz
          lobalan INTO :mylob_loc";
 
$stmt = oci_parse($conn, $sql);
 
// Boş bir OCI-Lob objesi oluşturuyoruz
$myLOB = oci_new_descriptor($conn, OCI_D_LOB);
 
// LOB loactor a bağlıyoruz.
oci_bind_by_name($stmt, ":mylob_loc", $myLOB, -1, OCI_B_CLOB);
 
// Sorguyu çalıştıyoruz (Default Transaction modunda)
oci_execute($stmt, OCI_DEFAULT)
    or die ("Unable to execute query\n");
 
//  Lob alana şimdi istediğimizi yazdırıyoruz
if ( !$myLOB->save('Tarih : '.date('H:i:s',time())) ) {
 
    // Hata olmuşsa geri sarıyoruz
    oci_rollback($conn);
 
} else {
 
    // başarıyla yazabildiysek commit ediyoruz.
    oci_commit($conn);
 
}
 
// kaynakları boşaltıp  veritabanı bağlantısını kesiyoruz.
oci_free_statement($stmt);
$myLOB->free();
oci_close($conn)

Blob Compression konusunda bilgi almak için de şu konuyu okuyabilirsiniz

Oracle Blob Compression

4000 byte’tan daha büyük verilerle çalışıyorsak LOB  alanlara ihtiyacımız olacaktır.   

Standart (basit) veritabanı tipleriyle çalışmak diğer datalarda olduğu gibi Oracle’da da oldukça kolay. Fakat dosya saklama – ya da stringe dönüşümünde veri bozulmaları yaşayabileceğimiz 4000 byte tan büyük datalarla çalışacaksak Oralce LOB (Long Objects) lara ihtiyacımız olacaktır. PHP ile Oracle LOB alanlarda  yapabileceğimiz işlemleri incelemden once kısaca LOB tipleri tanımlayalım  

Oracle LOB Objects     

 

  • BLOB, Binary verileri saklamak için kullanırır (Binary Long Object)
  • CLOB, Veritabanı karakter setinde normal karakterler saklamak için kullanılır (Characters Long Object)
  • NCLOB,Unicode datalar saklamak için kullanılır . PHP nin Oci8 eklentisinde bu yoktur.
  • BFILE, Veritabanı sunucusnda dosya adresini referans alarak sunucuda saklanacak dosyalar için kullanılır.
  •   

    Üzerinde işlem yapılan LOB alanlar biz boşaltana kadar geçici tablo alanında (Temporary Tablespace) saklanır .  Oracle 9i ve öncesinde bu tipler için table spacede ayrı ayrı saklama yeri oluşturuluyormuş bu yuzden eski sürümlerde bu tipler üzerinde işlem yaparken daha dikkatli olmamız söyleniyor.   

     LOB Saklama 
    Oracle 10g  her LOB hücresi için 128 TB kadar veri saklama kapasitesine sahipmiş. Bu Veri tabanı block boyutu ve yığınlama ayarlarında isteğe bağlı değiştirilebiliniyormuş.  LOB verilerinin saklanması 2 elemanla olur. LOB Content  ve LOB Locator. LOB Content   sadece LOB Locator’un adresini içerir. 
          Dahili LOB tipleri (BFILE dışında kalanlar) 4KB nin altında  olduğu sürece diğer tablo verileriyle aynı (stored in line in the table ) yerde saklanır.   lob alanlarınız 4 kb den küçükse isteklerinizin işlenip size gelmesi gayet hızlı olacaktır. fakat büyükse bu  tablo için yapılan SELECT sorgularında LOB sütunlarının dahil edilmesi sorgu sonucu almanızı yavaşlatacaktır.  

    LOB Kısıtlamaları  
     Lob alalar için en önemli kısıtlamalar. Sorgu dahilinde sıralama ve gruplama işlemleridir.  

    • Coğul Elemelerde  kullanılmaz
    • Sıralamalarda kullanılamaz
    • Gruplamalarda kullanulamaz
    • Birleştirmelede kullanılamaz
    • Primary Key olarak atanamaz
    • Unique index oluşturulamaz

    SELECT DISTINCT <lob_type>
    ORDER BY <lob_type>
    GROUP BY <lob_col>   

    dahil edemeyeceğimiz bu işlemler ile yine bu işlemleri kullanan  UNION -MINUS -INTERSECTION gibi tablo birleştirme işlemlerinide kısıtlamış olur.  

    PHP ve ORACLE LOB işlemleri (OCI-Lob Sınıfı):
       Bu sınıfla ilgili php manual de  maalesef cok sınıflı bilgi var.  php ile OCI LOB işlemleri yapmamız için kullanabileceğimiz bu sınıf dikkatimi çektiği üzere bir cok PHP IDE tarafından da complatorlara dahil edilmemiş.! 

    Yerel Sunucumda PHP 5.3 versiyonunda OCI-Lob sınıfının metodlarını incelemek istedim.
      

    OCI-Lob::load()          
    OCI-Lob::tell()          
    OCI-Lob::truncate()      
    OCI-Lob::erase()         
    OCI-Lob::flush()         
    OCI-Lob::setbuffering()  
    OCI-Lob::getbuffering()  
    OCI-Lob::rewind()        
    OCI-Lob::read()          
    OCI-Lob::eof()           
    OCI-Lob::seek()          
    OCI-Lob::write()         
    OCI-Lob::append()        
    OCI-Lob::size()          
    OCI-Lob::writetofile()   
    OCI-Lob::export()        
    OCI-Lob::import()        
    OCI-Lob::writetemporary()
    OCI-Lob::close()         
    OCI-Lob::save()          
    OCI-Lob::savefile()      
    OCI-Lob::free()           

    metodların hepsini maalesef işleyemeyeceğim fakat kullandıkça örnekleri de buraya yazmaya çalışacağım. 

    Çoğu zaman ilişkili tablolarımızda tablo sayısı  bir kaç taneyi geçebiliyor  ve genelde bunların sonuna ya da başına _ALT koyuyoruz (:  ama soyun sınırsız olduğunu düşündüğümüzde  bunu tek tabloda tutup  ATA_ID ya da PARENT_ID gibi kendisinin atasıyla ilişkilendirmek daha mantıklı oluyor. bu gibi durumlarda Recursive işlemlere ihtiyac duyuyoruz . ama bunu recursive olarak dataya sormak yerine  recursive işlemini dataya yapmak daha da mantıklıdır. bu işlemi yapan cümleciğimizin yapısı da  CONNECT BY PRIOR – START WITH anahtar  cumleciklerinden oluşuyor ilk once bir soyağacı tablosu örneği vermek istiyorum . ailem diye bir tablo oluşturalım

    0
    1
    2
    3
    4
    
    CREATE TABLE ailem(
     tckimlik int PRIMARY KEY,
     adi VARCHAR(30),
     baba_tc int
    );

    ailenin her ferdini bu tabloda ilişkili olarka tutabiliriz  baba_tc kendisinin babası olan kaydın tckimlik alanına eşit olacaktır.

    şimdi kayıtlarımızı ekleyelim

    0
    1
    2
    3
    4
    5
    6
    7
    
    INSERT INTO ailem (tckimlik,adi) VALUES (1,'Ömer');
    INSERT INTO ailem (tckimlik,adi,baba_tc) VALUES (2,'Yahya',1);
    INSERT INTO ailem (tckimlik,adi,baba_tc) VALUES (3,'Tufan',2);
    INSERT INTO ailem (tckimlik,adi,baba_tc) VALUES (4,'Savaş',2);
    INSERT INTO ailem (tckimlik,adi,baba_tc) VALUES (5,'Diyar',2);
    INSERT INTO ailem (tckimlik,adi,baba_tc) VALUES (6,'Barbaros',2);
    INSERT INTO ailem (tckimlik,adi,baba_tc) VALUES (7,'Yeğenim',6);
    INSERT INTO ailem (tckimlik,adi,baba_tc) VALUES (8,'Çocuğum (:',3);

    yandaki tablodan da gördüğümüz gibi  baba_tc alanı ile  kaydın babasını belirledik. bu iki sütun yardımı ile ağaç yapısnı oluşturabileceğimiz bir tablo yapımız oldu.

    şimdi ornek sorguyu yazalım

    0
    1
    2
    
    SELECT  adi,tckimlik,baba_tc
    FROM  ailem
    CONNECT BY PRIOR tckimlik=baba_tc

    bu sorgu sonucunda bize tüm kayıtlar ve varsa alt alt kayıtları da dönecektir. örnek resim :

    kayıtlar baba_tc ile geldi ama bu ne kadar işimize yarar (: her kayıt baba olarak ve her kaydın da varsa cocuğu geldi baba_tc ile zaten bu tabloda bir ilişki kurabiliyorduk bu bizim için bi anlam ifade etmedi conenct by sorgularında kullanabileceğimiz bir anahtar daha LEVEL  bu da bize kaydın derinliğini ya da nesil katını verir diyelim.

    örnek sorgu

    0
    1
    2
    
    SELECT  adi,tckimlik,baba_tc,LEVEL
    FROM  ailem
    CONNECT BY PRIOR tckimlik=baba_tc

    level bize derinlik verdi. resimdeki orneğe bakalım

    leveli 1 olan  ilk atalar 2- 3 diye arttıkça torun oluyor.

    buna bir de leveli kullanarak anlaşılabilir bir görüntü verebiliriz. lpad fonksiyonunu kullanarak  isimlerin başına “level”  kadar ” – ” attıralım..

    0
    1
    2
    3
    
    SELECT  LPAD('-',LEVEL,'-')|| adi sahis,tckimlik,baba_tc,LEVEL
    FROM  ailem
    START WITH baba_tc IS NULL
    CONNECT BY PRIOR tckimlik=baba_tc

    boylelikle kayıtlar daha anlaşılır oldu  kim kimin atası net olarak görülebiliyor.

    şimdi bu kayıtları üst kaydı göstererek tek satırda göstermeye çalışalım. bunun için de  SYS_CNNECT_BY_PATH() fonksiyonunu kullanacağız.

    örnek sorgu :

    0
    1
    2
    3
    
    SELECT tckimlik,adi, SYS_CONNECT_BY_PATH(adi, '->') AS konum
    FROM ailem
    CONNECT BY PRIOR tckimlik=baba_tc
    START WITH baba_tc IS NULL

    tablo :

    şimdi ise   her kaydı dosya yolu gibi PATH ‘i ile beraber  dededen ->toruna ikişkisiyle göstermeyi başardık  (:
    iyi çalışmalar…

    oracle regexp yeteneklerini kullanarak to_date fonksiyonunda hata verecek tarihleri önceden tespit edip hataya düşmeden null olarak dönmesini sağladık . önce fonksiyonu  vereyim sonrasında bi cümlem daha olacak (:

    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    
    CREATE OR REPLACE FUNCTION to_date2(txt IN VARCHAR2,Format IN Varchar2:='DD.MM.YYYY')
       RETURN VARCHAR2
    IS
       Gun   INT;
       Ay    INT;
       Yil   INT;
    BEGIN
       IF REGEXP_LIKE (
             txt,
             '(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.]((19|20)\d\d)'
          )
       THEN
          Gun :=
             TO_NUMBER(REGEXP_REPLACE (
                          txt,
                          '(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.]((19|20)\d\d)',
                          '\1'
                       ));
          Ay :=
             TO_NUMBER(REGEXP_REPLACE (
                          txt,
                          '(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.]((19|20)\d\d)',
                          '\2'
                       ));
          Yil :=
             TO_NUMBER(REGEXP_REPLACE (
                          txt,
                          '(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.]((19|20)\d\d)',
                          '\3'
                       ));
     
          IF MOD (Yil, 4) = 0
          THEN
             IF (Ay = 2 AND Gun > 29)
             THEN
                RETURN NULL;
             END IF;
          ELSIF (Ay = 2 AND Gun > 28)
          THEN
             RETURN NULL;
          END IF;
     
          IF (Ay <= 7)
          THEN
             IF (MOD (Ay, 2) = 1 AND Gun > 31) OR (MOD (Ay, 2) = 0 AND Gun > 30)
             THEN
                RETURN NULL;
             END IF;
          ELSIF (Ay > 7)
          THEN
             IF (MOD (Ay, 2) = 0 AND Gun > 31) OR (MOD (Ay, 2) = 1 AND Gun > 30)
             THEN
                RETURN NULL;
             END IF;
          END IF;
          RETURN TO_CHAR (to_date(Gun||'.'||Ay||'.'Yil),Format);
       END IF;
     
       RETURN NULL;
    END;
    /

    bunlar yerine to_date ve to_char fonksiyonlarını içeren bir fonskiyonla hata yakalandığında null dön diyebilirdik . fonksiyonun tek yaptığı 01/10.2009 gibi farklı işaretler kullanıldığında da ayırabilmek (: ama madem bu kadar uğraştım yayınliim dedim (:

    iyi çalışmalar

    © 2012 Tufan Suffusion theme by Sayontan Sinha