To access or change the value of an attribute, youuse dot notation: CREATE TYPE Address AS OBJECT street VARCHAR230, city VARCHAR220, state CHAR2, zip_code VARCHAR25 ; CREATE TYPE Stude
Trang 1Defining Object Constructors
Calls to methods of an uninitialized object raise the predefined exceptionNULL_SELF_DISPATCH When passed as arguments toIN parameters, attributes of anuninitialized object evaluate toNULL When passed as arguments toOUT orIN OUT
parameters, they raise an exception if you try to write to them
Accessing Object Attributes
You refer to an attribute by name To access or change the value of an attribute, youuse dot notation:
CREATE TYPE Address AS OBJECT ( street VARCHAR2(30), city VARCHAR2(20), state CHAR(2), zip_code VARCHAR2(5) );
CREATE TYPE Student AS OBJECT ( name VARCHAR2(20), home_address Address, phone_number VARCHAR2(10), status VARCHAR2(10), advisor_name VARCHAR2(20),
);
TheAddress attribute is an object type that has a zip_code attribute Ifs is a
Student object, you access the value of itszip_code attribute as follows:
s.home_address.zip_code
Defining Object Constructors
By default, you do not need to define a constructor for an object type The systemsupplies a default constructor that accepts a parameter corresponding to eachattribute
You might also want to define your own constructor:
■ To supply default values for some attributes You can ensure the values are correctinstead of relying on the caller to supply every attribute value
■ To avoid many special-purpose procedures that just initialize different parts of anobject
■ To avoid code changes in applications that call the constructor, when newattributes are added to the type The constructor might need some new code, for
Trang 2Calling Object Constructors
example to set the attribute to null, but its signature could remain the same so thatexisting calls to the constructor would continue to work
CONSTRUCTOR FUNCTION rectangle(length NUMBER, width NUMBER) RETURN SELF AS RESULT
);
/ CREATE OR REPLACE TYPE BODY rectangle AS CONSTRUCTOR FUNCTION rectangle(length NUMBER, width NUMBER) RETURN SELF AS RESULT
AS BEGIN SELF.length := length;
SELF.width := width;
We compute the area rather than accepting it as a parameter.
SELF.area := length * width;
RETURN;
END;
END;
/ DECLARE r1 rectangle;
r2 rectangle;
BEGIN We can still call the default constructor, with all 3 parameters.
Calling Object Constructors
Calls to a constructor are allowed wherever function calls are allowed Like allfunctions, a constructor is called as part of an expression, as the following exampleshows:
DECLARE r1 Rational := Rational(2, 3);
FUNCTION average (x Rational, y Rational) RETURN Rational IS BEGIN
.
END;
BEGIN r1 := average(Rational(3, 4), Rational(7, 11));
IF (Rational(5, 8) > r1) THEN .
END IF;
Trang 3Calling Object Methods
r := Rational(den => 6, num => 5); assign 5 to num, 6 to den
Calling Object Methods
Like packaged subprograms, methods are called using dot notation In the followingexample, you call methodnormalize(), which divides attributesnum andden (for
"numerator" and "denominator") by their greatest common divisor:
As the example below shows, you can chain method calls Execution proceeds fromleft to right First, member functionreciprocal() is called, then member procedure
normalize() is called
DECLARE
r Rational := Rational(6, 8);
BEGIN r.reciprocal().normalize;
dbms_output.put_line(r.num); prints 4 END;
In SQL statements, calls to a parameterless method require an empty parameter list Inprocedural statements, an empty parameter list is optional unless you chain calls, inwhich case it is required for all but the last call
You cannot chain additional method calls to the right of a procedure call because aprocedure is called as a statement, not as part of an expression For example, thefollowing statement is not allowed:
r.normalize().reciprocal; not allowedAlso, if you chain two function calls, the first function must return an object that can
be passed to the second function
For static methods, calls use the notationtype_name.method_name rather thanspecifying an instance of the type
Trang 4Sharing Objects through the REF Modifier
When you call a method using an instance of a subtype, the actual method that isexecuted depends on the exact declarations in the type hierarchy If the subtypeoverrides the method that it inherits from its supertype, the call uses the subtype'simplementation Or, if the subtype does not override the method, the call uses the
supertype's implementation This capability is known as dynamic method dispatch.
Sharing Objects through the REF Modifier
It is inefficient to pass copies of large objects from subprogram to subprogram It
makes more sense to pass a pointer instead A ref is a pointer to an object.
Sharing means that data is not replicated unnecessarily When a shared object isupdated, the change occurs in only one place, and any ref can retrieve the updatedvalues instantly
CREATE TYPE Home AS OBJECT ( address VARCHAR2(35), owner VARCHAR2(25), age INTEGER, style VARCHAR(15), floor plan BLOB, price REAL(9,2),
);
/ CREATE TABLE homes OF Home;
By revising object typePerson, you can model families, where several people sharethe same home You use the type modifierREF to declare refs, which hold pointers toobjects
CREATE TYPE Person AS OBJECT ( first_name VARCHAR2(10), last_name VARCHAR2(15), birthday DATE,
home_address REF Home, can be shared by family phone_number VARCHAR2(15),
ss_number INTEGER, mother REF Person, family members refer to each other father REF Person,
You cannot navigate through refs Given an expression such asx.attribute, where
x is a ref, PL/SQL cannot navigate to the table in which the referenced object is stored.For example, the following assignment is not allowed:
DECLARE p_ref REF Person;
phone_no VARCHAR2(15);
BEGIN phone_no := p_ref.phone_number; not allowed
Trang 5Manipulating Objects through SQL
You must use the functionDEREF or make calls to the packageUTL_REF to access theobject For some examples, see"Using Function DEREF" on page 12-20
Forward Type Definitions
You can refer only to schema objects that already exist In the following example, thefirstCREATE TYPE statement is not allowed because it refers to object type
Department, which does not yet exist:
CREATE TYPE Employee AS OBJECT ( name VARCHAR2(20),
dept REF Department, not allowed
);
CREATE TYPE Department AS OBJECT ( number INTEGER,
manager Employee,
);
Switching theCREATE TYPE statements does not help because the object types are
mutually dependent Object typeEmployee has an attribute that refers to object type
Department, and object typeDepartment has an attribute of typeEmployee Tosolve this problem, you use a specialCREATE TYPE statement called a forward typedefinition, which lets you define mutually dependent object types
To debug the last example, simply precede it with the following statement:
CREATE TYPE Department; forward type definition at this point, Department is an incomplete object type
The object type created by a forward type definition is called an incomplete object
type because (until it is defined fully) it has no attributes or methods
An impure incomplete object type has attributes but causes compilation errors because
it refers to an undefined type For example, the followingCREATE TYPE statementcauses an error because object typeAddress is undefined:
CREATE TYPE Customer AS OBJECT (
id NUMBER, name VARCHAR2(20), addr Address, not yet defined phone VARCHAR2(15)
);
This lets you defer the definition of object typeAddress The incomplete type
Customer can be made available to other application developers for use in refs
Manipulating Objects through SQL
You can use an object type in theCREATE TABLEstatement to specify the datatype of acolumn Once the table is created, you can use SQL statements to insert an object,select its attributes, call its methods, and update its state
Note: Access to remote or distributed objects is not allowed
In the SQL*Plus script below, theINSERT statement calls the constructor for objecttypeRational, then inserts the resulting object TheSELECT statement retrieves the
Trang 6Manipulating Objects through SQL
which returns aRationalvalue after swapping attributesnumandden Notice that atable alias is required when you reference an attribute or method (For an explanation,seeAppendix D.)
CREATE TABLE numbers (rn Rational, ) /
INSERT INTO numbers (rn) VALUES (Rational(3, 62)) inserts 3/62 /
SELECT n.rn.num INTO my_num FROM numbers n returns 3 /
UPDATE numbers n SET n.rn = n.rn.reciprocal() yields 62/3When you instantiate an object this way, it has no identity outside the database table.However, the object type exists independently of any table, and can be used to createobjects in other ways
In the next example, you create a table that stores objects of typeRational in its
rows Such tables, having rows of objects, are called object tables Each column in a
row corresponds to an attribute of the object type Rows can have different columnvalues
CREATE TABLE rational_nums OF Rational;
Each row in an object table has an object identifier, which uniquely identifies the
object stored in that row and serves as a reference to the object
Selecting Objects
Assume that you have run the following SQL*Plus script, which creates object type
Person and object tablepersons, and that you have populated the table:
CREATE TYPE Person AS OBJECT ( first_name VARCHAR2(15), last_name VARCHAR2(15), birthday DATE,
home_address Address, phone_number VARCHAR2(15)) /
CREATE TABLE persons OF Person /
The following subquery produces a result set of rows containing only the attributes of
Person objects:
BEGIN INSERT INTO employees another object table of type Person SELECT * FROM persons p WHERE p.last_name LIKE '%Smith';
To return a result set of objects, you must use the functionVALUE, which is discussed
in the next section
Using Function VALUE
As you might expect, the functionVALUE returns the value of an object.VALUE takes
as its argument a correlation variable (In this context, a correlation variable is a row
variable or table alias associated with a row in an object table.) For example, to return aresult set ofPerson objects, useVALUE as follows:
BEGIN INSERT INTO employees SELECT VALUE(p) FROM persons p
Trang 7Manipulating Objects through SQL
WHERE p.last_name LIKE '%Smith';
In the next example, you useVALUE to return a specificPerson object:
SELECT VALUE(p) INTO p1 FROM persons p
WHERE p.last_name = 'Kroll';
BEGIN
p1.last_name := p1.last_name || ' Jr';
Now, the localPerson object held byp1 has the last name'Kroll Jr'
Using Function REF
You can retrieve refs using the functionREF, which, likeVALUE, takes as its argument
a correlation variable In the following example, you retrieve one or more refs to
Person objects, then insert the refs into tableperson_refs:
BEGIN
INSERT INTO person_refs
SELECT REF(p) FROM persons p
WHERE p.last_name LIKE '%Smith';
The next example retrieves a ref and attribute at the same time:
SELECT REF(p) INTO p_ref FROM persons p
WHERE p.last_name = my_last_name;
UPDATE persons p
SET p = Person('Jill', 'Anders', '11-NOV-67', )
WHERE REF(p) = p_ref;
END;
Trang 8Manipulating Objects through SQL
Testing for Dangling Refs
If the object to which a ref points is deleted, the ref is left dangling, pointing to a
nonexistent object To test for this condition, you can use the SQL predicateISDANGLING For example, suppose columnmanager in relational tabledepartment
holds refs toEmployee objects stored in an object table You can use the following
UPDATE statement to convert any dangling refs into nulls:
UPDATE department SET manager = NULL WHERE manager IS DANGLING;
Using Function DEREF
You cannot navigate through refs within PL/SQL procedural statements Instead, youmust use the functionDEREF in a SQL statement to dereference a pointer, and get thevalue to which it points.DEREF takes a reference to an object, and returns the value ofthat object If the ref is dangling,DEREF returns a null object
The following example dereferences a ref to aPerson object You can select from thedummy tableDUAL because each object stored in an object table has a unique objectidentifier, which is part of every ref to that object
DECLARE p1 Person;
p_ref REF Person;
name VARCHAR2(15);
BEGIN /* Assume that p_ref holds a valid reference
to an object stored in an object table */
SELECT DEREF(p_ref) INTO p1 FROM dual;
name := p1.last_name;
You can useDEREF in successive SQL statements to dereference refs:
CREATE TYPE PersonRef AS OBJECT (p_ref REF Person) /
DECLARE name VARCHAR2(15);
pr_ref REF PersonRef;
pr PersonRef;
p Person;
BEGIN /* Assume pr_ref holds a valid reference */
SELECT DEREF(pr_ref) INTO pr FROM dual;
SELECT DEREF(pr.p_ref) INTO p FROM dual;
name := p.last_name;
END /The next example shows that you cannot use functionDEREF within proceduralstatements:
BEGIN p1 := DEREF(p_ref); not allowedWithin SQL statements, you can use dot notation to navigate through object columns
to ref attributes and through one ref attribute to another You can also navigatethrough ref columns to attributes by using a table alias For example, the followingsyntax is valid:
table_alias.object_column.ref_attribute table_alias.object_column.ref_attribute.attribute table_alias.ref_column.attribute
Trang 9Manipulating Objects through SQL
Assume that you have run the following SQL*Plus script, which creates object types
Address andPerson and object tablepersons:CREATE TYPE Address AS OBJECT (
street VARCHAR2(35), city VARCHAR2(15), state CHAR(2), zip_code INTEGER) /
CREATE TYPE Person AS OBJECT ( first_name VARCHAR2(15), last_name VARCHAR2(15), birthday DATE,
home_address REF Address, shared with other Person objects phone_number VARCHAR2(15))
/ CREATE TABLE persons OF Person /
Ref attributehome_address corresponds to a column in object tablepersons thatholds refs toAddress objects stored in some other table After populating the tables,you can select a particular address by dereferencing its ref:
DECLARE addr1 Address, addr2 Address, BEGIN
SELECT DEREF(home_address) INTO addr1 FROM persons p WHERE p.last_name = 'Derringer';
In the example below, you navigate through ref columnhome_address to attribute
street In this case, a table alias is required
DECLARE my_street VARCHAR2(25), BEGIN
SELECT p.home_address.street INTO my_street FROM persons p WHERE p.last_name = 'Lucas';
Inserting Objects
You use theINSERT statement to add objects to an object table In the followingexample, you insert aPerson object into object tablepersons:
BEGIN INSERT INTO persons VALUES ('Jenifer', 'Lapidus', );
Alternatively, you can use the constructor for object typePerson to insert an objectinto object tablepersons:
BEGIN INSERT INTO persons VALUES (Person('Albert', 'Brooker', ));
In the next example, you use theRETURNING clause to storePerson refs in localvariables Notice how the clause mimics aSELECT statement.You can also use the
RETURNING clause inUPDATE andDELETE statements
DECLARE
Trang 10Manipulating Objects through SQL
p2_ref REF Person;
BEGIN INSERT INTO persons p VALUES (Person('Paul', 'Chang', )) RETURNING REF(p) INTO p1_ref;
INSERT INTO persons p VALUES (Person('Ana', 'Thorne', )) RETURNING REF(p) INTO p2_ref;
To insert objects into an object table, you can use a subquery that returns objects of thesame type An example follows:
BEGIN INSERT INTO persons2 SELECT VALUE(p) FROM persons p WHERE p.last_name LIKE '%Jones';
The rows copied to object tablepersons2 are given new object identifiers No objectidentifiers are copied from object tablepersons
The script below creates a relational table nameddepartment, which has a column oftypePerson, then inserts a row into the table Notice how constructorPerson()
provides a value for columnmanager.CREATE TABLE department (
dept_name VARCHAR2(20), manager Person, location VARCHAR2(20)) /
INSERT INTO department VALUES ('Payroll', Person('Alan', 'Tsai', ), 'Los Angeles') /
The newPerson object stored in columnmanager cannot be referenced because it isstored in a column (not a row) and therefore has no object identifier
Updating Objects
To modify the attributes of objects in an object table, you use theUPDATEstatement, asthe following example shows:
BEGIN UPDATE persons p SET p.home_address = '341 Oakdene Ave' WHERE p.last_name = 'Brody';
UPDATE persons p SET p = Person('Beth', 'Steinberg', ) WHERE p.last_name = 'Steinway';
END;
Trang 11PL/SQL Language Elements
Grammar, which knows how to control even kings —Molière
This chapter is a quick reference guide to PL/SQL syntax and semantics It shows youhow commands, parameters, and other language elements are combined to formPL/SQL statements It also provides usage notes and short examples
This chapter contains these topics:
Trang 13Assignment Statement
Assignment Statement
An assignment statement sets the current value of a variable, field, parameter, orelement The statement consists of an assignment target followed by the assignmentoperator and an expression When the statement is executed, the expression isevaluated and the resulting value is stored in the target For more information, see
"Assigning Values to Variables" on page 2-16
collection_name
( index )
cursor_variable_name : host_cursor_variable_name
Trang 14Precompiler environment, indicator variables let you detect nulls or truncated values
in output host variables
By default, unless a variable is initialized in its declaration, it is initialized toNULL
every time a block or subprogram is entered Always assign a value to a variablebefore using that variable in an expression
You cannot assign nulls to a variable defined asNOT NULL If you try, PL/SQL raisesthe predefined exceptionVALUE_ERROR
Only the valuesTRUE,FALSE, andNULL can be assigned to a Boolean variable.You can assign the result of a comparison or other test to a Boolean variable
You can assign the value of an expression to a specific field in a record
You can assign values to all fields in a record at once PL/SQL allows aggregateassignment between entire records if their declarations refer to the same cursor ortable The following example copies values from all the fields of one record to another:
Trang 15Assignment Statement
DECLARE emp_rec1 emp%ROWTYPE;
emp_rec2 emp%ROWTYPE;
dept_rec dept%ROWTYPE;
BEGIN
Trang 16AUTONOMOUS_TRANSACTION Pragma
AUTONOMOUS_TRANSACTION Pragma
within a transaction A subprogram marked with this pragma can do SQL operationsand commit or roll back those operations, without committing or rolling back the data
in the main transaction For more information, see"Doing Independent Units of Workwith Autonomous Transactions" on page 6-35
You can apply this pragma to:
■ Top-level (not nested) anonymous PL/SQL blocks
■ Local, standalone, and packaged functions and procedures
■ Methods of a SQL object type
■ Database triggersYou cannot apply this pragma to an entire package or an entire an object type Instead,you can apply the pragma to each packaged subprogram or object method
You can code the pragma anywhere in the declarative section For readability, code thepragma at the top of the section
Once started, an autonomous transaction is fully independent It shares no locks,resources, or commit-dependencies with the main transaction You can log events,increment retry counters, and so on, even if the main transaction rolls back
Unlike regular triggers, autonomous triggers can contain transaction controlstatements such asCOMMIT andROLLBACK, and can issue DDL statements (such as
CREATE andDROP) through theEXECUTE IMMEDIATE statement
Changes made by an autonomous transaction become visible to other transactionswhen the autonomous transaction commits The changes also become visible to themain transaction when it resumes, but only if its isolation level is set toREADCOMMITTED (the default) If you set the isolation level of the main transaction to
SERIALIZABLE, changes made by its autonomous transactions are not visible to the
main transaction when it resumes
In the main transaction, rolling back to a savepoint located before the call to the
autonomous subprogram does not roll back the autonomous transaction Remember,
autonomous transactions are fully independent of the main transaction
If an autonomous transaction attempts to access a resource held by the maintransaction (which cannot resume until the autonomous routine exits), a deadlock can
PRAGMA AUTONOMOUS_TRANSACTION ;
autonomous_transaction_pragma
Trang 17The following example marks a packaged function as autonomous:
CREATE PACKAGE banking AS FUNCTION balance (acct_id INTEGER) RETURN REAL;
END banking;
/ CREATE PACKAGE BODY banking AS FUNCTION balance (acct_id INTEGER) RETURN REAL IS PRAGMA AUTONOMOUS_TRANSACTION;
my_bal REAL;
BEGIN NULL;
END;
END banking;
/ DROP PACKAGE banking;
The following example lets a trigger issue transaction control statements:
CREATE TABLE anniversaries AS SELECT DISTINCT TRUNC(hire_date) anniversary FROM employees;
ALTER TABLE anniversaries ADD PRIMARY KEY (anniversary);
CREATE TRIGGER anniversary_trigger BEFORE INSERT ON employees FOR EACH ROW DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN INSERT INTO anniversaries VALUES(TRUNC(:new.hire_date));
Only commits the preceding INSERT, not the INSERT that fired the trigger.
COMMIT;
EXCEPTION If someone else was hired on the same day, we get an exception because of duplicate values That's OK, no action needed.
WHEN OTHERS THEN NULL;
END;
/ DROP TRIGGER anniversary_trigger;
DROP TABLE anniversaries;
Related Topics
SERIALLY_REUSABLE Pragma
Trang 18Blocks
The basic program unit in PL/SQL is the block A PL/SQL block is defined by thekeywordsDECLARE,BEGIN,EXCEPTION, andEND These keywords partition theblock into a declarative part, an executable part, and an exception-handling part Onlythe executable part is required You can nest a block within another block whereveryou can place an executable statement For more information, see"Block Structure" onpage 1-4 and"Scope and Visibility of PL/SQL Identifiers" on page 2-14
type_definition
type_definition item_declaration
function_declaration procedure_declaration
SUBTYPE subtype_name IS base_type
( constraint ) NOT NULL
;
subtype_definition
Trang 20Declares a collection (index-by table, nested table, or varray) For the syntax of
collection_declaration, see"Collections" on page 13-21
fetch_statement forall_statement goto_statement if_statement loop_statement null_statement open_statement open_for_statement plsql_block raise_statement return_statement sql_statement
statement
Trang 21cursor_variable_declaration
Declares a cursor variable For the syntax ofcursor_variable_declaration, see
"Cursor Variables" on page 13-34
DECLARE
Signals the start of the declarative part of a PL/SQL block, which contains local
declarations Items declared locally exist only within the current block and all itssub-blocks and are not visible to enclosing blocks The declarative part of a PL/SQLblock is optional It is terminated implicitly by the keywordBEGIN, which introducesthe executable part of the block
PL/SQL does not allow forward references You must declare an item before
referencing it in any other statements Also, you must declare subprograms at the end
of a declarative section after all other program items
END
Signals the end of a PL/SQL block It must be the last keyword in a block Remember,
END does not signal the end of a transaction Just as a block can span multiple
transactions, a transaction can span multiple blocks
EXCEPTION
Signals the start of the exception-handling part of a PL/SQL block When an exception
is raised, normal execution of the block stops and control transfers to the appropriateexception handler After the exception handler completes, execution proceeds with thestatement following the block
If there is no exception handler for the raised exception in the current block, controlpasses to the enclosing block This process repeats until an exception handler is found
or there are no more enclosing blocks If PL/SQL can find no exception handler for the
exception, execution stops and an unhandled exception error is returned to the host
environment For more information, seeChapter 10
function_declaration
Declares a function For the syntax offunction_declaration, see"Functions" onpage 13-67
label_name
An undeclared identifier that optionally labels a PL/SQL block If used,label_name
must be enclosed by double angle brackets and must appear at the beginning of theblock Optionally,label_name(not enclosed by angle brackets) can also appear at the
end of the block
A global identifier declared in an enclosing block can be redeclared in a sub-block, inwhich case the local declaration prevails and the sub-block cannot reference the global
Trang 22Declares an instance of an object type For the syntax ofobject_declaration, see
"Object Types" on page 13-86
PL/SQL statements are free format That is, they can continue from line to line if you
do not split keywords, delimiters, or literals across lines A semicolon (;) serves as thestatement terminator
Example
The following PL/SQL block declares some variables, executes statements withcalculations and function calls, and handles errors that might occur:
Trang 23DECLARE numerator NUMBER := 22;
denominator NUMBER := 7;
the_ratio NUMBER;
BEGIN the_ratio := numerator/denominator;
dbms_output.put_line('Ratio = ' || the_ratio);
EXCEPTION WHEN ZERO_DIVIDE THEN dbms_output.put_line('Divide-by-zero error: can''t divide ' ||
Trang 24CASE Statement
CASE Statement
TheCASE statement chooses from a sequence of conditions, and executes acorresponding statement TheCASE statement evaluates a single expression andcompares it against several potential values, or evaluates multiple Boolean expressionsand chooses the first one that isTRUE
simple_case_statement ::=
[ <<label_name>> ]
CASE case_operand { WHEN when_operand THEN {statement;} }
[ ELSE {statement;} ] END CASE [ label_name ];
Keyword and Parameter Description
The value of theCASE operand andWHEN operands in a simpleCASE statement can beany PL/SQL type other than BLOB,BFILE, an object type, a PL/SQL record, anindex-by table, a varray, or a nested table
If theELSE clause is omitted, the system substitutes a default action For aCASE
statement, the default when none of the conditions matches is to raise a
CASE_NOT_FOUND exception For aCASE expression, the default is to returnNULL
Usage Notes
TheWHEN clauses are executed in order
EachWHEN clause is executed only once
After a matchingWHEN clause is found, subsequentWHEN clauses are not executed.The statements in aWHEN clause can modify the database and call non-deterministicfunctions
There is no "fall-through" as in the Cswitch statement Once aWHEN clause ismatched and its statements are executed, theCASE statement ends
TheCASE statement is appropriate when there is some different action to be taken foreach alternative If you just need to choose among several values to assign to avariable, you can code an assignment statement using aCASE expression instead.You can includeCASE expressions inside SQL queries, for example instead of a call totheDECODE function or some other function that translates from one value to another