PL/SQL Object Types
10.6. Mendefinisikan Object Types
Sebuah object type dapat merepresentasikan suatu entitas real-word (dunia nyata). Sebagai contoh, sebuah object type dapat merepresentasikan pelajar, rekening bank, layar komputer, angka relasional, atau struktur data seperti queue (antrian), stack, atau list. Bagian ini akan memberikan beberapa contoh lengkap, yang akan mengajarkan kepada kita banyak hal tentang desain object types dan menyiapkan kita untuk memulai menulis object type kita sendiri.
Sekarang, kita tidak dapat mendefinisikan object types di dalam sebuah PL/SQL block, subprogram, atau package. Namun, kita dapat mendefinisikan mereka secara interaktif di dalam SQL*Plus dengan menggunakan sintaks berikut ini:
CREATE [OR REPLACE] TYPE type_name
[AUTHID {CURRENT_USER | DEFINER}]
{ {IS | AS} OBJECT | UNDER supertype_name }
(
attribute_name datatype[, attribute_name datatype]...
[{MAP | ORDER} MEMBER function_spec,]
[{FINAL| NOT FINAL} MEMBER function_spec,]
[{INSTANTIABLE| NOT INSTANTIABLE} MEMBER function_spec,]
[{MEMBER | STATIC} {subprogram_spec | call_spec}
[, {MEMBER | STATIC} {subprogram_spec | call_spec}]...]
) [{FINAL| NOT FINAL}] [ {INSTANTIABLE| NOT INSTANTIABLE}];
[CREATE [OR REPLACE] TYPE BODY type_name {IS | AS}
{ {MAP | ORDER} MEMBER function_body;
| {MEMBER | STATIC} {subprogram_body | call_spec};}
[{MEMBER | STATIC} {subprogram_body | call_spec};]...
END;]
Klausa AUTHID menentukan apakah seluruh anggota methods dijalankan dengan privilege dari definer mereka (default) atau invoker mereka, dan apakah referensi tak terkualifikasi mereka kepada schema objects ditetapkan di dalam schema dari definer atau invoker.
10.6.1. Pengenalan PL/SQL Type Inheritance
PL/SQL mendukung sebuah single-inheritance model. Kita dapat mendefinisikan subtype dari object types. Subtypes ini mengandung seluruh attributes dan methods dari parent type (atau supertype). Subtypes dapat juga mengandung attributes tambahan dan methods tambahan, dan dapat mengesampingkan methods dari supertype-nya.
Kita dapat mendefinisikan apakah bisa atau tidak subtypes diperolah dari sebuah type khusus. Kita dapat juga mendefinisikan types dan methods yang tidak dapat di-instantiate secara langsung, hanya dengan mendeklarasikan subtypes yang meng-instantiate mereka.
Beberapa dari properti type dapat diubah secara dinamis dengan perintah ALTER TYPE. Ketika perubahan dilakukan terhadap supertype, baik melalui ALTER TYPE atau dengan mendefinisikan ulang supertype, subtype secara otomatis merefleksikan perubahan-perubahan tersebut.
Kita dapat menggunakan operator TREAT untuk menghasilhan hanya objek-objek dari subtype yang telah ditentukan.
Nilai-nilai dari functions REF dan DEREF dapat merepresentasikan baik type yang dideklarasikan dari table atau view, atau satu atau lebih dari subtypes-nya.
Contoh dari PL/SQL Type Inheritance
-- Menciptakan sebuah supertype dimana beberapa subtypes akan diperoleh. CREATE TYPE Person_typ AS OBJECT ( ssn NUMBER, name VARCHAR2(30), address VARCHAR2(100)) NOT FINAL;
-- Memperoleh sebuah subtype yang memiliki seluruh atribute dari supertype, -- ditambah dengan bebera atribut-atribut tambahan. CREATE TYPE Student_typ UNDER Person_typ ( deptid NUMBER, major VARCHAR2(30)) NOT FINAL; -- Because Student_typ is declared NOT FINAL, you can derive -- further subtypes from it. CREATE TYPE PartTimeStudent_typ UNDER Student_typ( numhours NUMBER); -- Derive another subtype. Because it has the default attribute -- FINAL, you cannot use Employee_typ as a supertype and derive -- subtypes from it. CREATE TYPE Employee_typ UNDER Person_typ( empid NUMBER, mgr VARCHAR2(30)); -- Define an object type that can be a supertype. Because the -- member function is FINAL, it cannot be overridden in any -- subtypes. CREATE TYPE T AS OBJECT (..., MEMBER PROCEDURE Print(), FINAL MEMBER FUNCTION foo(x NUMBER)...) NOT FINAL; -- We never want to create an object of this supertype. By using -- NOT INSTANTIABLE, we force all objects to use one of the subtypes -- instead, with specific implementations for the member functions. CREATE TYPE Address_typ AS OBJECT(...) NOT INSTANTIABLE NOT FINAL; -- These subtypes can provide their own implementations of -- member functions, such as for validating phone numbers and -- postal codes. Because there is no "generic" way of doing these -- things, only objects of these subtypes can be instantiated. CREATE TYPE USAddress_typ UNDER Address_typ(...); CREATE TYPE IntlAddress_typ UNDER Address_typ(...); -- Return REFs for those Person_typ objects that are instances of -- the Student_typ subtype, and NULL REFs otherwise. SELECT TREAT(REF(p) AS REF Student_typ) FROM Person_v p; -- Example of using TREAT for assignment... -- Return REFs for those Person_type objects that are instances of -- Employee_type or Student_typ, or any of their subtypes. SELECT REF(p) FROM Person_v P WHERE VALUE(p) IS OF (Employee_typ, Student_typ); -- Similar to above, but do not allow any subtypes of Student_typ. SELECT REF(p) FROM Person_v p WHERE VALUE(p) IS OF(ONLY Student_typ); -- The results of REF and DEREF can include objects of Person_typ -- and its subtypes such as Employee_typ and Student_typ. SELECT REF(p) FROM Person_v p; SELECT DEREF(REF(p)) FROM Person_v p;
10.6.2. Contoh Object Type: Stack
Sebuah stack menggenggam sebuah collectiont terurut dari data items. Stacks memiliki sebuah top dan sebuah bottom. Items dapat ditambahkan atau dihapus hanya dari bagian top. Sehingga, item terakhir yang ditambahkan ke sebuah stack merupakan item pertama yang dihapus. (Pikirkan stack seperti baki bersih yang disediakan di sebuah kafetaria). Operasi-operasi melakukan push dan pop update stack dengan tindakan last in, first out (LIFO) – terakhir kali masuk, pertama kali keluar.
Stacks memiliki banyak aplikasi. Sebagai contoh, mereka digunakan di dalam pemrograman sistem untuk memprioritaskan interupsi-interupsi dan untuk menangani rekursi. Implementasi sederhana dari sebuah stack menggunakan sebuah integer array, dengan sebuah akhir dari array tersebut merepresentasikan top dari stack tersebut.
PL/SQL menyediakan tipe data VARRAY, yang mengijinkan kita untuk mendeklarasikan variable-size arrays (varrays). Untuk mendeklarasikan varray attribute, pertama kita harus mndefinisikan type-nya. Namun, kita tidak dapat mendefinisikan types di dalam sebuah object type spec. Jadi, kita harus mendefinisikan sebuah standalone varray type, yang menentukan ukuran maksimumnya, seperti berikut ini:
CREATE TYPE IntArray AS VARRAY(25) OF INTEGER;
Sekarang, kita dapat menulis object type spec:
CREATE TYPE Stack AS OBJECT ( max_size INTEGER, top INTEGER, position IntArray, MEMBER PROCEDURE initialize, MEMBER FUNCTION full RETURN BOOLEAN, MEMBER FUNCTION empty RETURN BOOLEAN, MEMBER PROCEDURE push (n IN INTEGER), MEMBER PROCEDURE pop (n OUT INTEGER) );
Akhirnya, kita menulis object type body:
CREATE TYPE BODY Stack AS
MEMBER PROCEDURE initialize IS
BEGIN
top := 0;
/* Call constructor for varray and set element 1 to NULL. */
position := IntArray(NULL);
max_size := position.LIMIT; -- get varray size constraint
position.EXTEND(max_size - 1, 1); -- copy element 1 into 2..25
END initialize;
MEMBER FUNCTION full RETURN BOOLEAN IS
BEGIN
RETURN (top = max_size); -- return TRUE if stack is full
END full;
MEMBER FUNCTION empty RETURN BOOLEAN IS
BEGIN
RETURN (top = 0); -- return TRUE if stack is empty
END empty;
MEMBER PROCEDURE push (n IN INTEGER) IS
BEGIN
IF NOT full THEN
top := top + 1; -- push integer onto stack
position(top) := n;
ELSE -- stack is full
RAISE_APPLICATION_ERROR(-20101, ’stack overflow’);
END IF;
END push;
MEMBER PROCEDURE pop (n OUT INTEGER) IS
BEGIN
IF NOT empty THEN
n := position(top);
top := top - 1; -- pop integer off stack
ELSE -- stack is empty
RAISE_APPLICATION_ERROR(-20102, ’stack underflow’);
END IF;
END pop;
END;
Di dalam procedures push dan pop, kita menggunakan built-in procedure raise_application_error untuk memunculkan user-defined error messages. Dengan begitu, kita melaporkan errors kepada client program dan menghindari munculnya unhandled exceptions ke host environment. Client program mendapatkan sebuah PL/SQL exception, yang dapat diprosesnya dengan menggunakan error-reporting functions SQLCODE dan SQLERRM I dalam sebuah OTHERS exception handler. Di dalam contoh berikut ini, ketika sebuah exception dimunculkan, kita menampilkan Oracle error message terkait:
DECLARE
...
BEGIN
...
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(SQLERRM);
END;
Alternatifnya, program tersebut dapat menggunakan pragma EXCEPTION_INIT untuk memetakan error numbers yang dihasilkan oleh raise_application_error kepada exceptions bernama, seperti ditunjukkan oleh contoh berikut ini:
DECLARE
stack_overflow EXCEPTION;
stack_underflow EXCEPTION;
PRAGMA EXCEPTION_INIT(stack_overflow, -20101);
PRAGMA EXCEPTION_INIT(stack_underflow, -20102);
BEGIN
...
EXCEPTION
WHEN stack_overflow THEN
...
END;
10.6.3. Contoh Object Type: Ticket_Booth
Pikirkan sebuah rangkaian dari movie theaters, setiap theater dengan tiga layar. Setiap theater memiliki sebuah pojok penjualan tiket dimana tiket-tiket untuk tiga film berbeda dijual. Seluruh tiket dihargai $3.00. Secara periodik, tanda terima tiket dikumpulkan dan stok tiket diisi kembali.
Sebelum mendefinisikan sebuah object type yang merepresentasikan sebuah pojok penjualan tiket, kita harus memikirkan data dan operasi yang diperlukan. Untuk sebuah pojok penjualan tiket sederhana, object type memerlukan attributes untuk harga tiket, kuantitas tiket yang ada di tangan, dan tanda terima tiket. Juga diperlukan methods untuk operasi-operasi: pemesanan tiket, pengambilan inventory, pengisian stock, dan pengumpulan tanda terima.
Untuk tanda terima, kita menggunakan tiga elemen varray. Elemen 1, 2, dan 3 merekam tanda terima tiket untuk film 1, 2, dan 3. Untuk mendeklarasikan sebuah varray attribute, pertama kita harus mendefinisikan type-nya, seperti berikut:
CREATE TYPE RealArray AS VARRAY(3) OF REAL;
Sekarang, kita dapat menuliskan object type spec:
CREATE TYPE Ticket_Booth AS OBJECT ( price REAL, qty_on_hand INTEGER, receipts RealArray, MEMBER PROCEDURE initialize, MEMBER PROCEDURE purchase ( movie INTEGER, amount REAL, change OUT REAL), MEMBER FUNCTION inventory RETURN INTEGER, MEMBER PROCEDURE replenish (quantity INTEGER), MEMBER PROCEDURE collect (movie INTEGER, amount OUT REAL) );
Akhirnya, kita menulis object type body:
CREATE TYPE BODY Ticket_Booth AS
MEMBER PROCEDURE initialize IS
BEGIN
price := 3.00;
qty_on_hand := 5000; -- provide initial stock of tickets
-- call constructor for varray and set elements 1..3 to zero
receipts := RealArray(0,0,0);
END initialize;
MEMBER PROCEDURE purchase (
movie INTEGER,
amount REAL,
change OUT REAL) IS
BEGIN
IF qty_on_hand = 0 THEN
RAISE_APPLICATION_ERROR(-20103, ’out of stock’);
END IF;
IF amount >= price THEN
qty_on_hand := qty_on_hand - 1;
receipts(movie) := receipts(movie) + price;
change := amount - price;
ELSE -- amount is not enough
change := amount; -- so return full amount
END IF;
END purchase;
MEMBER FUNCTION inventory RETURN INTEGER IS BEGIN RETURN qty_on_hand; END inventory; MEMBER PROCEDURE replenish (quantity INTEGER) IS BEGIN qty_on_hand := qty_on_hand + quantity; END replenish; MEMBER PROCEDURE collect (movie INTEGER, amount OUT REAL) IS BEGIN amount := receipts(movie); -- get receipts for a given movie receipts(movie) := 0; -- reset receipts to zero END collect; END;
10.6.4. Contoh Object Type: Bank_Account
Sebelum mendefinisikan sebuah object type yang merepresentasikan sebuah bank account, pertama kita harus memikirkan data dan operasi-operasi yang diperlukan. Untuk sebuah rekening bank sederhana, object type memerlukan attributes untuk sebuah nomor rekening, saldo, dan status. Juga diperlukan methods untuk operasi-operasi: pembukaan rekening, verifikasi nomor rekening, penutupan rekening, deposit dana, penarikan dana, dan saldo akhir.
Pertama, kita menulis object type spec, seperti berikut:
CREATE TYPE Bank_Account AS OBJECT ( acct_number INTEGER(5), balance REAL, status VARCHAR2(10), MEMBER PROCEDURE open (amount IN REAL), MEMBER PROCEDURE verify_acct (num IN INTEGER), MEMBER PROCEDURE close (num IN INTEGER, amount OUT REAL), MEMBER PROCEDURE deposit (num IN INTEGER, amount IN REAL), MEMBER PROCEDURE withdraw (num IN INTEGER, amount IN REAL), MEMBER FUNCTION curr_bal (num IN INTEGER) RETURN REAL );
Kemudian, kita menulis object type body:
CREATE TYPE BODY Bank_Account AS
MEMBER PROCEDURE open (amount IN REAL) IS
-- open account with initial deposit
BEGIN
IF NOT amount > 0 THEN
RAISE_APPLICATION_ERROR(-20104, 'bad amount');
END IF;
SELECT acct_sequence.NEXTVAL INTO acct_number FROM dual;
status := 'open';
balance := amount;
END open;
MEMBER PROCEDURE verify_acct (num IN INTEGER) IS
-- check for wrong account number or closed account
BEGIN
IF (num <> acct_number) THEN
RAISE_APPLICATION_ERROR(-20105, 'wrong number');
ELSIF (status = ’closed’) THEN
RAISE_APPLICATION_ERROR(-20106, 'account closed');
END IF;
END verify_acct;
MEMBER PROCEDURE close (num IN INTEGER, amount OUT REAL) IS -- close account and return balance BEGIN verify_acct(num); status := 'closed'; amount := balance; END close;
MEMBER PROCEDURE deposit (num IN INTEGER, amount IN REAL) IS
BEGIN
verify_acct(num);
IF NOT amount > 0 THEN
RAISE_APPLICATION_ERROR(-20104, 'bad amount');
END IF;
balance := balance + amount;
END deposit;
MEMBER PROCEDURE withdraw (num IN INTEGER, amount IN REAL) IS
-- if account has enough funds, withdraw
-- given amount; else, raise an exception
BEGIN
verify_acct(num);
IF amount <= balance THEN
balance := balance - amount;
ELSE
RAISE_APPLICATION_ERROR(-20107, 'insufficient funds');
END IF;
END withdraw;
MEMBER FUNCTION curr_bal (num IN INTEGER) RETURN REAL IS BEGIN verify_acct(num); RETURN balance; END curr_bal; END;
10.6.5. Contoh Object Type: Rational Numbers
Sebuah rational number adalah sebuah angka yang dapat diekspresikan sebagai hasil bagi dari dua integer, sebuah pembilang dan sebuah penyebut. Seperti halnya kebangakan bahasa, PL/SQL tidak memiliki sebuah relational number type atau predefined operations pada rational numbers. Mari kita perbaiki kesalahan ini dengan mendefinisikan object type Relational. Pertama, kita menulis object type spec, seperti berikut:
CREATE TYPE Rational AS OBJECT ( num INTEGER, den INTEGER, MAP MEMBER FUNCTION convert RETURN REAL, MEMBER PROCEDURE normalize, MEMBER FUNCTION reciprocal RETURN Rational, MEMBER FUNCTION plus (x Rational) RETURN Rational, MEMBER FUNCTION less (x Rational) RETURN Rational, MEMBER FUNCTION times (x Rational) RETURN Rational, MEMBER FUNCTION divby (x Rational) RETURN Rational, PRAGMA RESTRICT_REFERENCES (DEFAULT, RNDS,WNDS,RNPS,WNPS) );
PL/SQL tidak memperbolehkan overloading dari operator-operator. Sehingga, kita harus mendefinisikan methods dengan nama plus(), less() (kata minus telah disediakan), times(), dan divby() dibandingkan overloading infix operators +, -, * dan /.
Berikutnya, kita menciptakan standalone stored function berikut ini, yang disebut dengan method normalize():
CREATE FUNCTION gcd (x INTEGER, y INTEGER) RETURN INTEGER AS
-- find greatest common divisor of x and y
ans INTEGER;
BEGIN
IF (y <= x) AND (x MOD y = 0) THEN
ans := y;
ELSIF x < y THEN
ans := gcd(y, x); -- recursive call
ELSE
ans := gcd(y, x MOD y); -- recursive call
END IF;
RETURN ans;
END;
Kemudian, kita menuliskan object type body, seperti berikut:
CREATE TYPE BODY Rational AS MAP MEMBER FUNCTION convert RETURN REAL IS -- convert rational number to real number BEGIN RETURN num / den; END convert;
MEMBER PROCEDURE normalize IS -- reduce fraction num / den to lowest terms g INTEGER; BEGIN g := gcd(num, den); num := num / g; den := den / g; END normalize;
MEMBER FUNCTION reciprocal RETURN Rational IS -- return reciprocal of num / den BEGIN RETURN Rational(den, num); -- call constructor END reciprocal;
MEMBER FUNCTION plus (x Rational) RETURN Rational IS -- return sum of SELF + x r Rational; BEGIN r := Rational(num * x.den + x.num * den, den * x.den); r.normalize; RETURN r; END plus;
MEMBER FUNCTION less (x Rational) RETURN Rational IS -- return difference of SELF - x r Rational; BEGIN r := Rational(num * x.den - x.num * den, den * x.den); r.normalize; RETURN r; END less;
MEMBER FUNCTION times (x Rational) RETURN Rational IS -- return product of SELF * x r Rational; BEGIN r := Rational(num * x.num, den * x.den); r.normalize; RETURN r; END times;
MEMBER FUNCTION divby (x Rational) RETURN Rational IS -- return quotient of SELF / x r Rational; BEGIN r := Rational(num * x.den, den * x.num); r.normalize; RETURN r; END divby; END;
| Buku ini membahas berbagai macam tip dan trik yang sangat berguna bagi Anda pembaca pengguna database Oracle. Pemula, mahasiswa, programmer, maupun database administrator yang mengharapkan solusi cepat dalam menangani permasalahan-permasalahan dalam penggunaan database Oracle dapat membaca buku ini. Anda tidak harus membaca buku ini secara urut karena buku ini di susun berdasarkan topik permasalahan, dan Anda dapat membaca topik-topik yang sesuai dengan permasalahan yang Anda hadapi. Dapat di beli di toko buku Gramedia, Gunung Agung, Uranus, Karisma dsb. Harga Rp. 24.800,- (157 halaman) |


[…] Silahkan melanjutkan membaca pembahasan PL/SQL Object Types […]