Professional Documents
Culture Documents
Steven Feuerstein
PL/SQL Evangelist, Quest Software
www.ToadWorld.com/SF
Definer Rights
– Whenever you executed a stored program, it runs
under the privileges of the schema in which the
program was compiled or defined.
Invoker Rights
– Oracle resolves all data references (table, view,
etc.) at run-time, based on the currently-connect
user and its privileges (directly granted or available
through roles).
Central
Central Code
Code schema
schema User/Data
User/Data schema
schema
PACKAGE acct_mgr PROCEDURE mng_account IS
make BEGIN
AUTHID modify ...
code.acct_mgr.destroy(...);
CURRENT_USER destroy END;
...FROM accounts
accounts table
WHERE...
invrole.sql
invdefinv.sql
invdefinv.tst
irdynsql.sql
invoker_rights_mode.sf
Copyright 2000-2007 Steven Feuerstein - Page 20
Invoker Rights and the PL/SQL Call Stack
Easy to define
Lots of immediate applications
Minimal learning curve
Low implementation risks
Optimizing compiler
– Recompile in 10g and experience 100% improvement in
performance (results may vary).
Compile-time warnings
– Now the PL/SQL compiler tells you more than simply
compilation errors.
Conditional compilation (10.2 only)
– "ifdef" like pre-processing for PL/SQL
Automated in-lining of local subprograms
– New to Oracle11g
10g_optimize_cfl.sql
http://www.oracle.com/technology/tech/pl_sql/htdocs/new_in_10gr1.htm
and then:
ALTER PROCEDURE bigproc COMPILE REUSE SETTINGS;
REM If you want to enable warning message number 06002 and all warnings in
REM the performance category, and treat warning 5005 as a "hard" compile error:
ALTER SESSION SET plsql_warnings =
'enable:06002', 'enable:performance', 'ERROR:05005';
cc_debug_trace.sql
Optimizer
– Go with the defaults!
Compile-time warnings
– Try them out, see how much value you can extract from
it.
Conditional compilation
– Lots of potential
– Smart tool support needed to make it feasible and
maintainable
Automatic inlining
– Useful, but probably in a relatively limited way
nested_table_example.sql
Copyright 2000-2007 Steven Feuerstein - Page 47
About Varrays
varray_example.sql
Copyright 2000-2007 Steven Feuerstein - Page 48
Wide Variety of Collection Methods
Obtain information about the collection
– COUNT returns number of rows currently defined in collection.
– EXISTS returns TRUE if the specified row is defined.
– FIRST/LAST return lowest/highest numbers of defined rows.
– NEXT/PRIOR return the closest defined row after/before the specified
row.
– LIMIT tells you the max. number of elements allowed in a VARRAY.
Modify the contents of the collection
– DELETE deletes one or more rows from the index-by table.
– EXTEND adds rows to a nested table or VARRAY.
– TRIM removes rows from a VARRAY.
Database Application
/ SGA Function
Not in cache; PGA
Request data
from database Application
Requests Data
Data found in
Database cache. Database Application
is not needed.
/ SGA Function
PGA
Application
Requests Data
emplu.pkg
emplu.tst
Copyright 2000-2007 Steven Feuerstein - Page 53
PGA Caching: Things to keep in mind
DECLARE
TYPE array_t1 IS TABLE OF NUMBER
INDEX BY BINARY_INTEGER;
TYPE array_t2 IS TABLE OF NUMBER
INDEX BY PLS_INTEGER;
TYPE array_t3 IS TABLE OF NUMBER
INDEX BY POSITIVE;
TYPE array_t4 IS TABLE OF NUMBER
INDEX BY NATURAL;
TYPE array_t5 IS TABLE OF NUMBER
INDEX BY VARCHAR2(64);
TYPE array_t6 IS TABLE OF NUMBER
INDEX BY VARCHAR2(32767);
TYPE array_t7 IS TABLE OF
INDEX BY NUMBER
employee.last_name%TYPE;
TYPE array_t8 IS TABLE OF NUMBER INDEX BY
types_pkg.subtype_t;
PROCEDURE mark_as_used (
list_in IN maxvarchar2_t
, value_in IN maxvarchar2_t
, case_sensitive_in IN BOOLEAN DEFAULT FALSE
) IS
l_name maxvarchar2_t :=
CASE case_sensitive_in WHEN TRUE THEN value_in
ELSE UPPER ( value_in ) END;
BEGIN
g_list_of_lists ( list_in ) ( l_name ) := TRUE;
END mark_as_used;
END string_tracker;
string_tracker2.*
string_tracker3.*
Copyright 2000-2007 Steven Feuerstein - Page 62
Other multi-level collection examples
cc_smartargs.pkb:
cc_smartargs.next_overloading
cc_smartargs.add_new_parameter
our_favorites :=
my_favorites MULTISET UNION DISTINCT dad_favorites; SQL: UNION
our_favorites :=
my_favorites MULTISET INTERSECT dad_favorites; SQL: INTERSECT
our_favorites :=
dad_favorites MULTISET EXCEPT my_favorites; SQL: MINUS
END;
10g_setops.sql
10g_string_nt.sql
10g_favorites.sql
10g*union*.sql
Copyright 2000-2007 Steven Feuerstein - Page 67
Oracle10g Distinct sets of values
Use the SET operator to work with distinct values, and determine if you have a set
of distinct values.
DECLARE
keep_it_simple strings_nt := strings_nt ();
BEGIN
keep_it_simple := SET (favorites_pkg.my_favorites);
favorites_pkg.show_favorites (
'DISTINCT SET', keep_it_simple);
END;
10g_set.sql
10g_favorites.pkg
Copyright 2000-2007 Steven Feuerstein - Page 68
How to choose your collection type
Use associative arrays when you need to...
– Work within PL/SQL code only
– Sparsely fill and manipulate the collection
– Take advantage of negative index values and string indexing
Use nested tables when you need to...
– Access the collection inside SQL
– Want to perform set operations
Use varrays when you need to...
– If you need to (or can) specify a maximum size to your
collection
– Access the collection inside SQL: better performance than
nested tables, since varrays are stored "in line."
global_temp_tab_vs_coll.sql
emplu*.*
Copyright 2000-2007 Steven Feuerstein - Page 75
11g The Oracle 11g Function Result Cache
11g_emplu*.*
Performance penalty
for many “context
switches”
Update... Update...
Update... Update...
Update... Update...
Update... Update...
Update... Update...
Update... Fewer context switches, Update...
same SQL behavior
Copyright 2000-2007 Steven Feuerstein - Page 82
Bulk Processing in PL/SQL
FORALL
– Use with inserts, updates and deletes.
– Move data from collections to tables.
BULK COLLECT
– Use with implicit and explicit queries.
– Move data from tables into collections.
In both cases, the "back back" end processing in the
SQL engine is unchanged.
– Same transaction and rollback segment management
– Same number of individual SQL statements will be
executed.
– But BEFORE and AFTER statement-level triggers only
fire once per FORALL statement.
Copyright 2000-2007 Steven Feuerstein - Page 83
Use BULK COLLECT INTO for Queries
DECLARE
Declare a TYPE employees_aat IS TABLE OF employees%ROWTYPE
collection of INDEX BY BINARY_INTEGER;
records to hold
l_employees employees_aat;
the queried data. BEGIN
SELECT *
BULK COLLECT INTO l_employees
Use BULK FROM employees; bulkcoll.sql
COLLECT to bulktiming.sql
retrieve all rows. FOR indx IN 1 .. l_employees.COUNT
LOOP
process_employee (l_employees(indx));
Iterate through the END LOOP;
END;
collection
contents with a
loop. WARNING! BULK COLLECT will not raise
NO_DATA_FOUND if no rows are found.
Always check contents of collection to confirm that
something was retrieved.
Copyright 2000-2007 Steven Feuerstein - Page 84
Limit the number of rows returned by BULK
COLLECT
CREATE OR REPLACE PROCEDURE bulk_with_limit
(deptno_in IN dept.deptno%TYPE)
IS
CURSOR emps_in_dept_cur IS
SELECT * FROM emp
WHERE deptno = deptno_in;
bulkexc.sql
Copyright 2000-2007 Steven Feuerstein - Page 87
DBMS_ERRLOG (Oracle10gR2)
Allows DML statements to execute against all rows,
even if an error occurs.
– The LOG ERRORS clause specifies how logging should
occur.
– Use the DBMS_ERRLOG package to associate a log
table with DML operations on a base table.
Much faster than trapping errors, logging, and then
continuing/recovering.
You should consider using LOG ERRORS with
FORALL (instead of SAVE EXCEPTIONS) so that
you can obtain all error information!
– But there are some differences
dbms_errlog.*
in behavior. save_exc_vc_dbms_errlog.sql
cfl_to_bulk7.sql
Copyright 2000-2007 Steven Feuerstein - Page 88
Bulk Processing Conclusions
nocopy*.*
string_nocopy.*
AFTER STATEMENT IS
BEGIN
...
mutating.sql END AFTER STATEMENT;
11g_compound_mutating.sql END full_mfe_excuse_transaction;
Copyright 2000-2007 Steven Feuerstein - Page 93
11g Specifying order of trigger firing
multiple_triggers.sql
trigger_conflict.sql
Copyright 2000-2007 Steven Feuerstein - Page 94
11g Use sequences in native PL/SQL!
11g_native_sequence.sql
Copyright 2000-2007 Steven Feuerstein - Page 95
11g Using CONTINUE in a loop
You can now tell PL/SQL to terminate execution of the
current loop body and immediately go on to the next
iteration of that loop.
BEGIN
<<outer_loop >>
FOR o_index IN 1 .. my_list.COUNT
LOOP
<<inner_loop>>
FOR i_index IN your_list.FIRST .. your_list.LAST
LOOP
... lots of code
/* Skip the rest of this and the outer
loop if condition is met. */
CONTINUE outer_loop WHEN condition_is_met;
... more inner loop logic
END LOOP inner_loop;
... more outer loop logic
END LOOP outer_loop;
END;
Copyright 2000-2007 Steven Feuerstein - Page 96
11g Reference fields of records in FORALL
Prior to 11g, you could not reference a field of
a record in FORALL. Instead, you have
SQL> DECLARE
2 TYPE two_columns_rt IS RECORD ( to break out the
3 employee_id employees.employee_id%TYPE data into separate
4 , salary employees.salary%TYPE collections.
5 );
6 TYPE id_name_list_tt IS TABLE OF two_columns_rt INDEX BY PLS_INTEGER;
7 l_list id_name_list_tt; Very irritating.
8 BEGIN
9 SELECT employee_id, salary
10 BULK COLLECT INTO l_list FROM employees;
11 Oracle11g now
12 FOR idx IN 1 .. l_list.COUNT LOOP
13 l_list (idx).salary := apply_cola (l_list (idx).salary);
lets you do this.
14 END LOOP; BUT...
15 It is not
16 FORALL idx IN 1 .. l_list.COUNT
17 UPDATE employees SET salary = l_list (idx).salary
documented!
18 WHERE employee_id = l_list (idx).employee_id;
19 END;
20 /
UPDATE employees SET salary = l_list (idx).salary 11g_field_of_record.sql
*
ERROR at line 17:
PLS-00436: implementation restriction: cannot reference fields of BULK In-BIND
Copyright 2000-2007 Steven Feuerstein - Page 97
11g PL/Scope
Identify all declarations for the specified set of programs whose names do not start with "L_".
11g_plscope.sql
plw*.sql files
Copyright 2000-2007 Steven Feuerstein - Page 100
Oracle11g PL/SQL: Easier to use, faster to
execute, expanded capabilities
Function result cache a very elegant solution to static
data querying
PL/Scope offers wonderful new analytical capabilities
on our code base
Fewer gaps in functionality
– Dynamic SQL interoperability, CONTINUE, FOLLOWS for
triggers, etc.
Now all we have to do is convince our management to
upgrade to Oracle11g!
DBMS_SQL
– A large and complex built-in package that made
dynamic SQL possible in Oracle7 and Oracle8.
Native Dynamic SQL
– A new (with Oracle8i), native implementation of
dynamic SQL that does almost all of what
DBMS_SQL can do, but much more easily and
usually more efficiently.
Which should you use?
Here's
CREATE a handy
OR REPLACE and tabCount
FUNCTION simple utility
( based on NDS:
tab IN VARCHAR2, whr IN VARCHAR2 := NULL, sch IN VARCHAR2 := NULL)
RETURN INTEGER
IS Specify schema, table and
retval INTEGER;
BEGIN
WHERE clause...
EXECUTE IMMEDIATE
'SELECT COUNT(*) FROM ' || NVL (sch, USER) ||
'.' || tab || ' WHERE ' || NVL (whr, '1=1') INTO retval;
RETURN retval;
END;
desccols.pkg
desccols.tst
RETURN retval;
... tabfunc_scalar.sql
END lotsa_names;
You can use table functions to "stream" data through several stages
within a single SQL statement.
– Example: transform one row in the stocktable to two rows in the tickertable.
BEGIN
INSERT INTO tickertable
SELECT *
FROM TABLE (stockpivot (CURSOR (SELECT *
FROM stocktable)));
END;
/
tabfunc_setup.sql
Copyright 2000-2007 Steven Feuerstein - Page 132 tabfunc_pipelined.sql
Enabling Parallel Execution
You can use pipelined functions with the Parallel Query
option to avoid serialization of table function execution.
Include the PARALLEL_ENABLE hint in the program
header.
– Choose a partition option that specifies how the function's
execution should be partitioned.
– "ANY" means that the results are independent of the order in
which the function receives the input rows (through the REF
CURSOR).
objtype.sql
Copyright 2000-2007 Steven Feuerstein - Page 138
"Real" object types have methods
Constructor
– A function that returns an instance of this object type, used to
initialize that instance before use.
Static
– A subprogram applied to the object type as a whole, not any
particular instance
Member
– A subprogram applied to an instance of an object type
Use SELF to refer to the current instance.
– Not allowed in static methods.
You can call packaged code from within an object body.
tmr.ot
Copyright 2000-2007 Steven Feuerstein - Page 140 thisuser.*
More on Constructor Functions
CREATE TYPE tmr_t AS OBJECT (
Always pass SELF ...
CONSTRUCTOR FUNCTION tmr_t (
as an IN OUT SELF IN OUT tmr_t,
name IN VARCHAR2,
argument. repetitions IN INTEGER
)
– SELF is assumed for );
RETURN SELF AS RESULT
food.ot
DECLARE
TYPE foodstuffs_nt IS TABLE OF food_t; Declare a nested
table
fridge_contents foodstuffs_nt
:= foodstuffs_nt (
food_t ('Eggs benedict', 'PROTEIN', 'Farm'),
dessert_t ('Strawberries and cream', 'FRUIT',
'Backyard', 'N', 2001),
cake_t (
'Chocolate Supreme', 'CARBOHYDATE', 'Kitchen',
'Y', 2001, 8, 'Happy Birthday, Veva'
)
);
Insert three different
BEGIN
objects in the collection,
...
each of a different type.
SQL> DECLARE
4 mmm_good food_t :=
5 dessert_t ('Super Brownie', 'CARBOHYDRATE',
6 'my oven', 'Y', 1994);
7 BEGIN
8 DBMS_OUTPUT.PUT_LINE (mmm_good.contains_chocolate);
9 END;
10 /
DBMS_OUTPUT.PUT_LINE (mmm_good.contains_chocolate);
*
ERROR at line 8:
PLS-00302: component 'CONTAINS_CHOCOLATE' must be declared
food2.ot
Copyright 2000-2007 Steven Feuerstein - Page 153
Creating and Overriding Methods
Most real-world object types will have both
attributes and methods, programs that
perform operations on attributes.
With inheritance, you can:
– inherit supertype methods
– override or replace supertype methods with
subtype implementations
– add completely new methods
food2.ot
Copyright 2000-2007 Steven Feuerstein - Page 155
Disallowing Overrides
11g_gen_invoc.sql
Object tables
The REF function and UTL_REF
Object comparisons
– MAP and ORDER
Object views
– INSTEAD OF triggers
object_ref.sql
UTL_REF.SELECT_OBJECT
– Retrieves a copy of the object specified by the REF.
UTL_REF.LOCK_OBJECT
– Locks and optionally retrieves a copy of the specified
object.
UTL_REF.UPDATE_OBJECT
– Replaces the object specified by the REF with the object
in the parameter list.
UTL_REF.DELETE_OBJECT
– Deletes the object pointed to by the REF.
DECLARE
l_dinner food_t;
l_dessert dessert_t;
BEGIN
IF l_dinner > l_dessert THEN
...
Attribute-level comparison
– Check explicitly in your code based on attribute values.
Default SQL
– Simple equality test of each attribute, only works with scalars-
only object types.
– Not too useful; primary key values will never match.
MAP member method
– Map an object 'value" to a datatype that Oracle knows how to
compare.
ORDER member method
– Compares two objects and returns a flag indicating their relative
order.
UTL_FILE
– Not nearly as limited as before!
DBMS_OUTPUT.PUT_LINE
– Big strings! Big buffer! (Oracle10g Release 2)
DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
– Finally, the missing link has been added.
DBMS_RANDOM
– Straightforward random number generation
UTL_RECOMP
– Powerful recompile capability
UTL_MAIL
– Send emails with ease
utl_file_dir = /tmp
utl_file_dir = /accounts/newdev
Can only read from a file opened with the "R" mode.
Maximum length for lines to read/write files is 32K, but
you need to specify that length explicitly.
The NO_DATA_FOUND exception is raised if you read
past the end of the file.
– You might want to build your own GET_LINE which handles
the exception and returns an EOF Boolean statusexec_ddl_from_file.sql
flag.
Copyright 2000-2007 Steven Feuerstein - Page 181 getnext.sp infile.sf
Writing to a File
DECLARE
fid UTL_FILE.FILE_TYPE;
BEGIN
fid := UTL_FILE.FOPEN ('c:\temp', 'test.txt', 'W');
UTL_FILE.PUT_LINE (fid, 'UTL_FILE');
UTL_FILE.PUT (fid, 'is so much fun');
UTL_FILE.PUTF (fid, ' that I never\nwant to %s', '&1');
UTL_FILE.FCLOSE (fid);
END;
If you do not close the file, you will not see the data you have (supposedly) written
to that file.
You can close a single file with FCLOSE or all open files with FCLOSE_ALL.
You should close files in exception handlers to make sure that files are not left
"hanging" open.
fremove.sql
fileIO92.pkg
frename.sql
fileIO92.pkg
Copyright 2000-2007 Steven Feuerstein - Page 186
Obtaining attributes of a file
CREATE OR REPLACE FUNCTION flength (
location_in IN VARCHAR2,
file_in IN VARCHAR2
) How big is a file? What is its
IS
RETURN PLS_INTEGER
block size? Does the file
TYPE fgetattr_t IS RECORD ( exist?
fexists BOOLEAN,
file_length PLS_INTEGER, All valuable questions.
);
block_size PLS_INTEGER
All answered with a call to
UTL_FILE.FGETATTR.
fgetattr_rec fgetattr_t;
BEGIN
UTL_FILE.fgetattr (
location => location_in,
filename => file_in,
fexists => fgetattr_rec.fexists,
file_length => fgetattr_rec.file_length,
block_size => fgetattr_rec.block_size
);
flength.sql
RETURN fgetattr_rec.file_length;
fileIO92.pkg
END flength;
JFile.java
Copyright 2000-2007 Steven Feuerstein - Page 188 xfile.pkg
DBMS_UTILITY.FORMAT_ERROR_BACKTR
ACE
Long-standing challenge in PL/SQL:
Backtrace.sql
backtrace.sql
Copyright 2000-2007 Steven Feuerstein - Page 192 bt.pkg
DBMS_OUTPUT: relief in sight!
randomizer.*
pick_winners_randomly.*
http://quest-pipelines.com/pipelines/dba/PLVision/plvision.htm