Saya memiliki pengembang yang mengajukan pertanyaan menarik kepada saya baru-baru ini. Dia sedang mengerjakan masalah di mana nilai numerik disimpan dalam tabel tetapi ketika dia menanyakan tabel itu di PL/SQL Developer, itu akan menunjukkan angka nol setelah digit terakhir. Dia bertanya-tanya apakah ini berkontribusi pada masalah yang dia coba debug. Pengembang perlu mengetahui apakah Oracle menyimpan angka nol tersebut.
Tanggapan saya adalah bahwa Oracle tidak menyimpan angka nol tambahan. Oracle hanya menyimpan eksponen dan mantissa dari nomor tersebut. Oracle tidak memasukkan nilai numerik dengan nol. Pengembang sekarang tahu bahwa masalahnya bukan pada data dalam database, melainkan pada sesuatu yang dilakukan oleh platform pengembangannya.
Tapi apakah pernyataan saya benar? Sering kali saya membuat pernyataan tentang cara kerja Oracle secara internal tetapi kemudian harus kembali dan memvalidasi pernyataan saya atau membuktikan bahwa itu salah yang pasti mengarah ke pernyataan yang benar.
Untuk menguji pernyataan saya, saya membuat tabel sederhana dan memasukkan data ke dalamnya.
SQL> create table test_tab (val number(38,5)); Table created. SQL> insert into test_tab values (25); 1 row created. SQL> insert into test_tab values (25.0); 1 row created. SQL> insert into test_tab values (25.2); 1 row created. SQL> insert into test_tab values (25.20); 1 row created. SQL> commit; Commit complete. SQL> select * from test_tab; VAL ---------- 25 25 25.2 25.2
Di SQL*Plus, kami tidak melihat angka nol yang tertinggal meskipun saya secara eksplisit menambahkannya. Nilai 25 dan 25.0 serta 25.2 dan 25.20 semuanya terlihat sama. Tapi mungkin beginilah cara SQL*Plus menampilkan nilainya. Jadi mari kita buang blok data untuk melihat bagaimana tepatnya Oracle menyimpan nilai-nilai ini.
SQL> select file_id,block_id,blocks 2 from dba_extents where segment_name='TEST_TAB'; FILE_ID BLOCK_ID BLOCKS ---------- ---------- ---------- 6 128 8 SQL> alter system dump datafile 6 block min 128 block max 135; System altered.
Saya harus menentukan file dan nomor blok untuk segmen yang saya buat. Saya kemudian mengeluarkan perintah untuk membuang konten blok data ke file jejak. Saat Anda melihat di file jejak, cari kata kunci “block_row_dump” dan Anda dapat melihat isi dari baris ini di dump di bawah ini:
block_row_dump: tab 0, row 0, @0x1f92 tl: 6 fb: --H-FL-- lb: 0x1 cc: 1 col 0: [ 2] c1 1a tab 0, row 1, @0x1f8c tl: 6 fb: --H-FL-- lb: 0x1 cc: 1 col 0: [ 2] c1 1a tab 0, row 2, @0x1f85 tl: 7 fb: --H-FL-- lb: 0x1 cc: 1 col 0: [ 3] c1 1a 15 tab 0, row 3, @0x1f7e tl: 7 fb: --H-FL-- lb: 0x1 cc: 1 col 0: [ 3] c1 1a 15 end_of_block_dump
Kita bisa melihat dari blok dump nilai pertama panjangnya 2 byte dan terdiri dari karakter hex "C1 1A". Baris kedua memiliki nilai yang sama persis! Ini penting karena memverifikasi klaim awal saya bahwa Oracle tidak menyimpan nol tambahan untuk baris kedua dalam tabel. Jika ada nol ekstra, panjangnya tidak akan menjadi 2 byte. Untuk baris ketiga dan keempat, kita bisa melihat nilai hex yang identik, “C1 1A 15”.
Tapi mari kita pastikan bahwa nilai heksagonal ini sesuai dengan data kita. Untuk melakukannya, kita akan menggunakan prosedur DBMS_STATS.CONVERT_RAW_VALUE.
SQL> set serveroutput on SQL> declare 2 n number; 3 begin 4 dbms_stats.convert_raw_value('C11A',n); 5 dbms_output.put_line(n); 6 end; 7 / 25 PL/SQL procedure successfully completed. SQL> declare 2 n number; 3 begin 4 dbms_stats.convert_raw_value('C11A15',n); 5 dbms_output.put_line(n); 6 end; 7 / 25.2 PL/SQL procedure successfully completed.
Jadi nilai hex "C1 1A" adalah representasi internal (mentah) dari '25' dan "C1 1A 15" adalah 25,2 seperti yang kita harapkan.
Moral dari cerita ini adalah bahwa terkadang ketika Anda merasa tahu cara kerja Oracle secara internal, Anda mungkin masih harus menyusun kasus uji untuk memvalidasi pernyataan Anda.