Sunteți pe pagina 1din 29

Gee Whiz!

New PL/SQL Toys


in Oracle10g
Steven Feuerstein
steven@stevenfeuerstein.com
www.quest.com, www.qnxo.com,
www.oracleplsqlprogramming.com
Copyright 2004-2005 Steven Feuerstein - Page 1
Software used in presentation

 You can download all my training


materials and demonstration scripts
from:
http://oracleplsqlprogramming.com/resources.html

 All scripts I run may be obtained from:


http://oracleplsqlprogramming.com/downloads/demo.zip

name of file
Copyright 2004-2005 Steven Feuerstein - Page 2
New but not overwhelming
(learning curve-wise)

 PL/SQL gets a whole lot faster – and you don't have


to lift a finger
 The compiler now tells you about problems in your
code
 DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
 FORALL is lots more flexible.
 Nested table unveil their MULTISET-edness.
 Oh, yes, and then there are...
– Alternative quoting mechanism
– Regular expressions

Copyright 2004-2005 Steven Feuerstein - Page 3


Wow! An optimizing compiler!

 Yes, the PL/SQL compiler now has the ability to


automatically optimize your code.
– Possible rearrangements to the code itself (under the covers).
 You can choose the level of optimization through
the plsql_optimization_level setting:
– 2 Most aggressive, maximum possible code transformations,
biggest impact on compile time. [default]
– 1 Smaller scale change, less impact on compile times
– 0 Pre-10g compilation without optimization
ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL = 0;
Copyright 2004-2005 Steven Feuerstein - Page 4
Optimizing compiler details

 Oracle retains optimizer settings on a module-by-


module basis. When you recompile a particular
module with non-default settings, the settings will
"stick," allowing you to recompile later using REUSE
SETTINGS. For example:
ALTER PROCEDURE bigproc COMPILE PLSQL_OPTIMIZE_LEVEL = 0;

 and then:
ALTER PROCEDURE bigproc COMPILE REUSE SETTINGS;

 All compiler settings for modules are available in the


USER_PLSQL_OBJECT_SETTINGS view.
Copyright 2004-2005 Steven Feuerstein - Page 5
Cursor FOR Loop ... or BULK COLLECT?

 Why would you ever use a cursor FOR loop (or


other LOOP) now that you can perform a BULK
COLLECT?
– If you want to do complex processing on each row as
it is queried – and possibly halt further fetching.
– You are retrieving many rows and cannot afford to use
up the memory (large numbers of users).
 Otherwise, moving to BULK COLLECT is a smart
move!
– Oracle10g will automatically convert CFL to BULK
COLLECT in some circumstances!
cfl_to_bulk.sql
10g_optimize_cfl.sql
Copyright 2004-2005 Steven Feuerstein - Page 6
Wow! Compile-time warnings!

 You can now enable compiler warnings, helping


you avoid nuisance issues in your code.
– Generally, these are not severe errors, but potential problems
with code structure or performance.
 To use compiler warnings, you must turn them
on in your session.
[ENABLE | DISABLE | ERROR]:[ALL|SEVERE|INFORMATIONAL|PERFORMANCE|warning_number]

REM To enable all warnings in your session execute:


ALTER SESSION SET plsql_warnings = 'enable:all‘;

REM If you want to enable warning message number 06002 and all warnings in
REM the performance category except warning number 07202, execute:
ALTER SESSION SET plsql_warnings =
'enable:06002', 'enable:performance' , 'disable:07202';

Copyright 2004-2005 Steven Feuerstein - Page 7


Compiler time warnings - example

 Check for unreachable code….


SQL> CREATE OR REPLACE PROCEDURE dead_code IS
2 x NUMBER := 10;
3 BEGIN
4 IF x = 10 THEN
5 x := 20;
6 ELSE
7 x := 100; -- dead code
8 END IF;
9 END dead_code;
10 /
 
SP2-0804: Procedure created with compilation warnings
 
SQL> show err
Errors for PROCEDURE DEAD_CODE:
 
LINE/COL ERROR
-------- -----------------------------------------------------------------
7/7 PLW-06002: Unreachable code
plw*.sql

Copyright 2004-2005 Steven Feuerstein - Page 8


Getting info about program settings

 Check the ALL_PLSQL_OBJECT_SETTINGS


for information about warnings status,
optimization level, etc.
 By the way, Oracle9i introduced
ALL_PROCEDURES, which gives you
information about the individual programs
defined in your schema.
– AUTHID, PIPELINED, DETERMINISTIC, etc.

Copyright 2004-2005 Steven Feuerstein - Page 9


DBMS_UTILITY.FORMAT_ERROR_BACKTRACE

Long-standing challenge in PL/SQL:

How can I find the line number on which an


error was raised in PL/SQL?

 Before Oracle10g, the only way is to let the error


go unhandled in your PL/SQL code!
 DBMS_UTILITY.FORMAT_ERROR_STACK
only gives you the full error message.
– And is recommended by Oracle in place of SQLERRM.
In Oracle10g, we have "back trace"!
Copyright 2004-2005 Steven Feuerstein - Page 10
Letting the error go unhandled…

CREATE OR REPLACE PROCEDURE proc1 IS


BEGIN
DBMS_OUTPUT.put_line ('running proc1');
RAISE NO_DATA_FOUND;
END;
/
CREATE OR REPLACE PROCEDURE proc2 IS
l_str VARCHAR2(30)
:= 'calling proc1';
BEGIN
DBMS_OUTPUT.put_line (l_str);
proc1;
END;
/
CREATE OR REPLACE PROCEDURE proc3 IS ERROR at line 1:
BEGIN ORA-01403: no data found
DBMS_OUTPUT.put_line ('calling proc2'); ORA-06512: at "SCOTT.PROC1", line 4
proc2; ORA-06512: at "SCOTT.PROC2", line 8
END; ORA-06512: at "SCOTT.PROC3", line 5
/ ORA-06512: at line 3

Backtrace.sql
Copyright 2004-2005 Steven Feuerstein - Page 11
Displaying the “error stack” inside PL/SQL

CREATE OR REPLACE PROCEDURE proc3


IS
BEGIN
DBMS_OUTPUT.put_line ('calling proc2');
proc2;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line (
DBMS_UTILITY.FORMAT_ERROR_STACK);
END;
/

SQL> exec proc3


calling proc2
calling proc1
running proc1
backtrace.sql
ORA-01403: no data found

Copyright 2004-2005 Steven Feuerstein - Page 12


Displaying the contents of BACKTRACE

CREATE OR REPLACE PROCEDURE proc3


IS
BEGIN
DBMS_OUTPUT.put_line ('calling proc2');
proc2;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line ('Error stack at top level:');
DBMS_OUTPUT.put_line (DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
END;
/

SQL> exec proc3


calling proc2
calling proc1
running proc1
Error stack at top level:
ORA-06512: at "SCOTT.PROC1", line 5
ORA-06512: at "SCOTT.PROC2", line 7
ORA-06512: at "SCOTT.PROC3", line 5

Copyright 2004-2005 Steven Feuerstein - Page 13 bt.pkg


The BACKTRACE stack with re-RAISEs

CREATE OR REPLACE PROCEDURE proc1 IS


BEGIN
… SQL> exec proc3
EXCEPTION calling proc2
WHEN OTHERS THEN calling proc1
DBMS_OUTPUT.put_line ( running proc1
'Error stack in block where raised:'); Error stack in block where raised:
DBMS_OUTPUT.put_line ( ORA-06512: at "SCOTT.PROC1", line 5
DBMS_UTILITY.format_error_backtrace);
RAISE; Error stack at top level:
END; ORA-06512: at "SCOTT.PROC1", line 11
/ ORA-06512: at "SCOTT.PROC2", line 7
CREATE OR REPLACE PROCEDURE proc3 IS ORA-06512: at "SCOTT.PROC3", line 5
BEGIN
DBMS_OUTPUT.put_line ('calling proc2'); Program owner = SCOTT
proc2; Program name = PROC1
EXCEPTION Line number = 11
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line ('Error stack at top level:');
DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_backtrace);
bt.show (DBMS_UTILITY.format_error_backtrace);END;
/
Copyright 2004-2005 Steven Feuerstein - Page 14
The BACKTRACE stack with new RAISE
CREATE OR REPLACE PROCEDURE proc1
IS
BEGIN
DBMS_OUTPUT.put_line ('running proc1');
RAISE NO_DATA_FOUND;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line ('Error stack in block where raised:');
DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_backtrace);
RAISE;
END; SQL> exec proc3
/ calling proc2
calling proc1
CREATE OR REPLACE PROCEDURE proc2 running proc1
IS Error stack in block where raised:
BEGIN ORA-06512: at "SCOTT.PROC1", line 5
DBMS_OUTPUT.put_line ('calling proc1');
proc1; Error stack at top level:
EXCEPTION ORA-06512: at "SCOTT.PROC2", line 9
WHEN OTHERS ORA-06512: at "SCOTT.PROC3", line 5
THEN
RAISE VALUE_ERROR; Program owner = SCOTT
END; Program name = PROC2
Copyright
/ 2004-2005 Steven Feuerstein - Page 15 Line number = 9
More flexibility with FORALL

 In Oracle10g, the FORALL driving array no


longer needs to be processed sequentially.
 Use the INDICES OF clause to use only the row
numbers defined in another array.
 Use the VALUES OF clause to use only the
values defined in another array.

Copyright 2004-2005 Steven Feuerstein - Page 16


Oracle10g Using INDICES OF

 It only DECLARE
TYPE employee_aat IS TABLE OF employee.employee_id%TYPE
processes INDEX BY PLS_INTEGER;
l_employees employee_aat;
the rows TYPE boolean_aat IS TABLE OF BOOLEAN
INDEX BY PLS_INTEGER;
with row l_employee_indices boolean_aat;

numbers BEGIN
l_employees (1) := 7839;
matching l_employees (100) := 7654;
l_employees (500) := 7950;
the defined --
l_employee_indices (1) := TRUE;
rows of the l_employee_indices (500) := TRUE;
--
driving FORALL l_index IN INDICES OF l_employee_indices

array. UPDATE employee


SET salary = 10000
WHERE employee_id = l_employees (l_index);
END;

Copyright 2004-2005 Steven Feuerstein - Page 17 10g_indices_of.sql


Oracle10g Using VALUES OF

DECLARE
 It only TYPE employee_aat IS TABLE OF employee.employee_id%TYPE

processes INDEX BY PLS_INTEGER;


l_employees employee_aat;
the rows TYPE indices_aat IS TABLE OF PLS_INTEGER
INDEX BY PLS_INTEGER;
with row l_employee_indices
BEGIN
indices_aat;

numbers l_employees (-77) := 7820;


l_employees (13067) := 7799;
matching l_employees (99999999) := 7369;

the content --
l_employee_indices (100) := -77;
of a row in l_employee_indices (200) := 99999999;
--
the driving FORALL l_index IN VALUES OF l_employee_indices
UPDATE employee
array. SET salary = 10000
WHERE employee_id = l_employees (l_index);
END;

Copyright 2004-2005 Steven Feuerstein - Page 18 10g_values_of.sql


Nested Tables unveil their
MULTISET-edness

 Oracle10g introduces high-level set operations


on nested tables (only).
– Nested tables are “multisets,” meaning that theoretically there is
no order to their elements. This makes set operations of critical
importance for manipulating nested tables. .
 You can now…
– Check for equality and inequality
– Obtain UNION, INTERSECT and MINUS of two NTs
– Determine if there are duplicates, remove them, etc.

Copyright 2004-2005 Steven Feuerstein - Page 19


Oracle10g Check for equality and inequality

 Just use the basic operators….


DECLARE
TYPE clientele IS TABLE OF VARCHAR2 (64);
group1 clientele := clientele ('Customer 1', 'Customer 2');
group2 clientele := clientele ('Customer 1', 'Customer 3');
group3 clientele := clientele ('Customer 3', 'Customer 1');
BEGIN
IF group1 = group2 THEN
DBMS_OUTPUT.put_line ('Group 1 = Group 2');
ELSE
DBMS_OUTPUT.put_line ('Group 1 != Group 2');
END IF;

IF group2 != group3 THEN


DBMS_OUTPUT.put_line ('Group 2 != Group 3');
ELSE
DBMS_OUTPUT.put_line ('Group 2 = Group 3');
END IF;
END; 10g_compare.sql
Copyright 2004-2005 Steven Feuerstein - Page 20 10g_compare_old.sql
Oracle10g UNION, INTERSECT, MINUS

 Straightforward, with the MULTISET keyword.


BEGIN
our_favorites := my_favorites MULTISET UNION dad_favorites;
show_favorites ('MINE then DAD', our_favorites);

our_favorites := dad_favorites MULTISET UNION my_favorites;


show_favorites ('DAD then MINE', our_favorites);

our_favorites := my_favorites MULTISET UNION DISTINCT dad_favorites;


show_favorites ('MINE then DAD with DISTINCT', our_favorites);

our_favorites := my_favorites MULTISET INTERSECT dad_favorites;


show_favorites ('IN COMMON', our_favorites);

our_favorites := dad_favorites MULTISET EXCEPT my_favorites;


show_favorites ('ONLY DAD''S', our_favorites);
END;
10g_setops.sql
10g_string_nt.sql
Copyright 2004-2005 Steven Feuerstein - Page 21 10g_favorites.sql
10g*union*.sql
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 ('FULL SET', favorites_pkg.my_favorites);

p.l (favorites_pkg.my_favorites IS A SET, 'My favorites distinct?');


p.l (favorites_pkg.my_favorites IS NOT A SET, 'My favorites NOT distinct?');

favorites_pkg.show_favorites (
'DISTINCT SET', keep_it_simple);

p.l (keep_it_simple IS A SET, 'Keep_it_simple distinct?');


p.l (keep_it_simple IS NOT A SET, 'Keep_it_simple NOT distinct?');

END;

10g_set.sql
Copyright 2004-2005 Steven Feuerstein - Page 22 10g_favorites.pkg
Oracle10g Determining subsets of data
 Use the SUBMULTISET operator to determine if a nested table contains only
elements that are in another nested table.

BEGIN
p.l (favorites_pkg.my_favorites
SUBMULTISET OF favorites_pkg.eli_favorites
, 'Father follows son?');

p.l (favorites_pkg.eli_favorites
SUBMULTISET OF favorites_pkg.my_favorites
, 'Son follows father?');

p.l (favorites_pkg.my_favorites
NOT SUBMULTISET OF favorites_pkg.eli_favorites
, 'Father doesn''t follow son?');

p.l (favorites_pkg.eli_favorites
NOT SUBMULTISET OF favorites_pkg.my_favorites
, 'Son doesn''t follow father?');
END; 10g_submultiset.sql
Copyright 2004-2005 Steven Feuerstein - Page 23 10g_favorites.pkg
Oracle10g Various Oracle10g improvements

 Alternative quoting mechanism


 Integer and floating point data type
improvements
 Compiler time warnings (hurray!)
 Optimizing compiler (who would have thought!)
 Regular expression support

Copyright 2004-2005 Steven Feuerstein - Page 24


Oracle10g Alternative quoting mechanism

 What do you do when you need to put a single quote inside a literal string?
– Before Oracle10g, you could sometimes tear your hair out.
– Now just specify an alternative quote character.

Literal using old Literal using new Actual Value


quoting mechanism quoting mechanism
'TZ=''CDT6CST''' q'(TZ='CDT6CST')' TZ='CDT6CST'

'''' q'-'-' '

'It''s here' q'[It's here]' It's here

'''''' nq'^''^' ''

Copyright 2004-2005 Steven Feuerstein - Page 25 10g_quotes.sql


Integer and floating point data type
Oracle10g
improvements

 Oracle now uses “machine arithmetic,” rather than C


library arithmetic, for all 32-bit INTEGER types
(BINARY_INTEGER and its subtypes)
– Previously, only PLS_INTEGER was so blessed. So now you can use
whichever type you want and not feel concerned about a performance hit.
 Support for IEEE 754 compliant floating point numbers to
both SQL and PLSQL: single precision BINARY_FLOAT,
and the double precision BINARY_DOUBLE.
– Faster and better for scientific number crunching.

Copyright 2004-2005 Steven Feuerstein - Page 26


Oracle10g Regular expression support

 Oracle10g supports the use of regular


expressions via four new built-in functions:
REGEXP_LIKE, REGEXP_INSTR,
REGEXP_SUBSTR, and REGEXP_REPLACE.
– Available in both SQL and PL/SQL
– Gives you much more flexibility and power in processing text,
through the use of “meta-characters.”
 Various examples on the next page.

Copyright 2004-2005 Steven Feuerstein - Page 27


Oracle10g Regular expression examples

IF REGEXP_LIKE(phone_number,'^\(?212\)?'
THEN
-- Begins with 212, optionally enclosed by parentheses
APPLY_NYC_SURCHARGE;
END IF;

-- get the leading number part of the address


-- (up to a whitespace character)

street_number :=
REGEXP_SUBSTR(address_line1, '[[:digit:]]+[:space:]');

-- change the domain part of the email addresses, by replacing


-- everything between the @ and the '.com' with new domain name

DBMS_OUTPUT.PUT_LINE (
REGEXP_REPLACE(email_address, '@.*\.com','@new_domain.com'));

Copyright 2004-2005 Steven Feuerstein - Page 28


Really nice stuff, mostly transparent

 Oracle10g offers some major new functionality,


but the most important stuff (optimizing,
compiler warnings) are transparent.
– Just upgrade and start having fun!
 As PL/SQL matures, enhancements will
naturally fill in gaps of functionality that respond
to more specialized interests.
– Don't worry if you don't see a need for features like
INDICES OF right now; the main thing is to grow
your awareness of what is possible.
Copyright 2004-2005 Steven Feuerstein - Page 29

S-ar putea să vă placă și