21st century plsql with 11g

202
pyright 2000-2007 Steven Feuerstein - Page 1 21 st Century PL/SQL Blast off to the faster, smarter, easier world of Oracle PL/SQL in Oracle10g and Oracle11g Steven Feuerstein PL/SQL Evangelist, Quest Software www.ToadWorld.com/SF

Upload: webanddb

Post on 11-Apr-2015

704 views

Category:

Documents


4 download

DESCRIPTION

*Brought to you by WebandDB.com

TRANSCRIPT

Page 1: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 1

21st Century PL/SQL

Blast off to thefaster, smarter, easier world

of Oracle PL/SQLin Oracle10g and Oracle11g

Steven FeuersteinPL/SQL Evangelist, Quest Software

www.ToadWorld.com/SF

Page 2: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 2

Two days of the newest, best, most important features of Oracle PL/SQL

The new PL/SQL Compiler– Optimizing compiler, compile-time warnings, conditional

compilation

Collections– String-based indexes, multi-level collections, high level set

operations for nested tables, table functions, and more.

High Performance PL/SQL– A roundup of key features that will help you speed up

performance of your PL/SQL applications

Other Oracle 11g New Features

Continued....

Page 3: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 3

More of the newest, best, most important features of Oracle PL/SQL

Dynamic SQL– Overview, Dynamic PL/SQL, method 4 dynamic SQL, when

and how to use DBMS_SQL.

Table Functions– Improve performance, hide complexity

Object types in PL/SQL– For the object-oriented in all of us...

Handy built-in package functionality– Read and write files; Random value generation; Send email,

recompile code; Miscellaneous wonderful capabilities in DBMS_OUTPUT and DBMS_UTILITY.

Page 4: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 4

So...why listen to me?Because I am a programmer obsessed...

And I build production applications....

Page 5: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 5

Enough about me. What about you?

How many years working on Oracle? What version of Oracle are you using? Are you a developer, DBA, or both? Do you write frontend code, too? What sort? Do we have any dev mgrs or team leads? Are you writing new applications, maintaining

existing apps or customizing OTS software? What IDE do you use to write code?

– Anybody still using ONLY SQL*Plus + editor?

Page 6: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 6

How to benefit most from this session

Watch, listen, focus on concepts and principles. Download and use any of my the training materials:

You have my permission to use all these materials to do internal trainings and build your own applications.– But remember: they are not production ready.– Modify them to fit your needs and then test them!

filename_from_demo_zip.sql

Download and use any of my scripts (examples, performance scripts, reusable code) from the same location: the demo.zip file.

http://www.ToadWorld.com/SFPL/SQL Obsession

Page 7: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 7

First, some PL/SQL fundamentals

The STANDARD package and how to be a PL/SQL sleuth

The PL/SQL run-time memory architecture Invoker rights

– Running code under the current user's authority

Autonomous transactions– Control the scope of commits and rollbacks

Page 8: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 8

The STANDARD Package and the Rdbms/Admin Directory

Much of what we consider to be the base PL/SQL language is defined in the STANDARD package.– One of two "default" packages; the other is

DBMS_STANDARD.

You can view the contents of the STANDARD package (and other "supplied" packages by visiting the appropriate variation of:

$ORACLE_HOME/Rdbms/Admin

standard_demo.sql

Page 9: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 9

Code and Data in Shared Memory

PL/SQL is an interpretative language. The source code is “partially compiled” into an intermediate form (“p-code”).– The p-code is loaded into the shared pool when any

element of that code (package or stand-alone program) is referenced.

The partially-compiled code is shared among all users who have EXECUTE authority on the program/package.

Each user (Oracle session) has its own copy of any data structures defined within the program/package.– Distinct sets of in-memory data (not shared among

different users) are stored in the Process Global Area.

Page 10: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 10

System Global Area (SGA) of RDBMS Instance

PL/SQL in Shared Memory

Shared Pool

Large Pool

Reserved Pool

show_empscalc_totals upd_salaries

Select * from emp

Shared SQL

Pre-parsedUpdate emp Set sal=...

Library cache

Session 1 memory (PGA/UGA)

emp_rec emp%rowtype;tot_tab tottabtype;

Session 2 memory (PGA/UGA)

emp_rec emp%rowtype;tot_tab tottabtype;Session 1

Session 2mysess.pkg

sess2.sqlshow_memory.sp

Page 11: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 11

Execution Mode Options for PL/SQL

Review of definer rights Introduction of invoker rights A look at some of the nuances

Page 12: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 12

Two options for resolving data references

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).

Page 13: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 13

About Definer Rights

Allows you to centralize access to and control of underlying data structures.

Ignores roles and relies on directly-granted privileges.

But it can be a source of confusion and architectural problems.

Orders

OE Data

OE CodeOrder_Mgt

Cancel

Sam_Sales

PlaceClose Old

Orders

XCannot alter

table directly.

Note: Oracle built-in packages have long had the capability of running

under the invoker's authority.

Page 14: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 14

Problems with Definer Rights

Deployment & maintenance– Must install module in all remote databases where needed– In some databases, each user has own copy of table(s),

requiring copy of stored module Security

– No declarative way to restrict privileges on certain modules in a package -- it's all or nothing, unless you write code in the package to essentially recreate roles programmatically.

– Difficult to audit privileges Sure would be nice to have a choice...and now you

do!

Page 15: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 15

For top level modules:

For modules with separate spec and body, AUTHID goes only in spec, and must be at the package level.– Holds true for packages and object types.

Invoker Rights Syntax

CREATE [ OR REPLACE ] <module type> [ AUTHID { DEFINER | CURRENT_USER } ]AS ...

Page 16: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 16

"Reflection" Capability of Invoker Rights

With invoker rights, you can execute code owned by another schema, yet have all references to data structures "reflect back" into your own schema.

User/Data schemaUser/Data schema

accounts table

PROCEDURE mng_account ISBEGIN ... code.acct_mgr.destroy(...);END;

Central Code schemaCentral Code schema

PACKAGE acct_mgr

...FROM accounts WHERE...

destroy

modify

make

AUTHID

CURRENT_USER

Page 17: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 17

When Invoker Rights Applies

Resolution against invoker's privileges is made for these statements:– SELECT, INSERT, UPDATE, and DELETE data

manipulation statements – The LOCK TABLE transaction control statement – OPEN and OPEN-FOR cursor control statements – All dynamic SQL statements

For all other statements, resolution is by the owner's privileges.– This includes ALL code references. – Ah, but perhaps there is a way around this restriction!

Page 18: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 18

Roles and Privileges

With definer rights, roles are disabled and ignored. – All references are resolved against directly granted

privileges. With invoker rights, roles are enabled and

used for privilege checking. – You can even use dynamic SQL to set roles for the

session, altering how the reference is resolved at run-time.

– Exception: if the CURRENT_USER programs was called directly or indirectly by a definer-rights subprogram.

invrole.sql

Page 19: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 19

When writing code with the intention of relying on invoker rights, the data object referenced may not be present in the code's schema. – You need some kind of "template" against which to

successfully compile the code.

Two options; either create a...– Synonym to any of the possible resolved objects.– Local, "dummy" object to allow the code to compile,

knowing that it will never be used at run-time.

Compiling with "Template" Objects

Page 20: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 20

Invoker-Definer Precedence

If the first program in the execution stack is defined with invoker rights, then it executes under the session user's authority.

When and if a definer rights program is called in the stack, the "current user" is set to the owner of the definer rights program.

All subsequent calls in the stack are resolved according to the privileges of that schema.

invdefinv.sqlinvdefinv.tstirdynsql.sql

invoker_rights_mode.sf

Page 21: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 21

Invoker Rights and the PL/SQL Call Stack

As mentioned earlier, the call stack (A called B calls C) is frozen at the time of compilation.– The AUTHID CURRENT_USER clause does not

apply - at least not directly But you can achieve the same effect by

embedding your PL/SQL program call within a dynamic PL/SQL statement.– Then the call to the program is resolved at runtime.– And AUTHID CURRENT_USER will be applied to

that statement!invoker_plsql.sql

Page 22: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 22

Autonomous Transactions

Prior to Oracle8i, a COMMIT or ROLLBACK in any program in your session committed or rolled back all changes in your session.– There was only one transaction allowed per connection.

You can now define a PL/SQL block to execute as an "autonomous transaction".– Any changes made within that block can be saved or reversed without

affecting the outer or main transaction.

CREATE OR REPLACE PROCEDURE loginfo ( code IN PLS_INTEGER, msg IN VARCHAR2)AS PRAGMA AUTONOMOUS_TRANSACTION;

Page 23: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 23

When to Use Autonomous Transactions

Reusable Application Components– ATs are more or less required in the new distributed

application architecture of the Internet. Logging Mechanism

– Solves problems of error logs in database tables, with log entries a part of your transaction.

Call functions within SQL that change the database.

Issue commits and rollbacks inside DB triggers.

Page 24: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 24

Logging with ATs

logger.splog81.pkglog81*.tst

CREATE OR REPLACE PACKAGE BODY log IS PROCEDURE putline ( code_in IN INTEGER, text_in IN VARCHAR2 ) IS PRAGMA AUTONOMOUS_TRANSACTION; BEGIN INSERT INTO logtab VALUES (code_in, text_in, SYSDATE, USER, SYSDATE, USER, rec.machine, rec.program ); COMMIT;

EXCEPTION WHEN OTHERS THEN ROLLBACK; END;END;

retry.pkgretry.tst

Save on successful exit

Avoid inter-dependencies with

the main transaction.

Don't forget to rollback on error!

Page 25: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 25

Tips and Gotchas with ATs

An AT program that executes DML must COMMIT or ROLLBACK before terminating, or an error is raised.– If you only query, COMMIT/ROLLBACK is not required.

The AT PRAGMA can be used only with individual programs and top-level anonymous blocks.– You cannot define an entire package or nested

anonymous block as an AT.

The AT PRAGMA goes in the body of packages.– You cannot tell by looking at the package spec if you are

calling ATs or not -- and this info is not available in the data dictionary.

Page 26: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 26

Tips and Gotchas, continued

The Oracle initialization parameter TRANSACTIONS specifies the maximum number of concurrent transactions. – Which might be exceeded if autonomous transactions

(running concurrently with main transaction) are not taken into account.

Any changes committed in an AT are visible in the outer transaction.– You can use the SET TRANSACTION ISOLATION

LEVEL SERIALIZABLE to indicate that you do not want the changes visible until the outer transaction commits.

– Place the SET TRANSACTION statement in the outer transaction.

autonserial.sqlauton_in_sql.sqlautontrigger*.sql

Page 27: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 27

Tips and Gotchas, continued

Avoid mutating table error for triggers that only query from the mutating table by making the trigger an autonomous transaction.– But not that you will not be able to see the

changes to that row from the trigger.

Watch out for deadlocks!– If you change programs that formerly assumed

shared locks to ATs, then you might suddenly experience deadlocks.

Page 28: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 28

Autonomous Transactions - Summary

Easy to define Lots of immediate applications Minimal learning curve Low implementation risks

You should immediately explore opportunities to utilize this feature.

Page 29: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 29

The New PL/SQL Compiler

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

Page 30: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 30

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_optimize_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 = 1;

10g_optimize_cfl.sql

Oracle10g

Page 31: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 31

Learn about the PL/SQL optimizer

PL/SQL Just Got Faster – Explains the workings of the PL/SQL compiler and runtime system and

shows how major improvements on this scale are indeed possible.

PL/SQL Performance Measurement Harness – Describes a performance experiment whose conclusion is the large

factors quoted above. We’ve provided a downloadable kit to enable you to repeat the experiment yourself.

Freedom, Order, and PL/SQL Optimization – Intended for professional PL/SQL programmers, explores the use and

behavior of the new compiler.

PL/SQL Performance — Debunking the Myths– Re-examines some old notions about PL/SQL performance.

http://www.oracle.com/technology/tech/pl_sql/htdocs/new_in_10gr1.htm

Page 32: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 32

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:

and then:

ALTER PROCEDURE bigproc COMPILE PLSQL_OPTIMIZE_LEVEL = 1;

ALTER PROCEDURE bigproc COMPILE REUSE SETTINGS;

Page 33: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 33

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, and treat warning 5005 as a "hard" compile error: ALTER SESSION SET plsql_warnings = 'enable:06002', 'enable:performance', 'ERROR:05005';

Oracle10g

Page 34: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 34

Compiler time warnings - example

Check for “unreachable end” code….SQL> CREATE OR REPLACE PROCEDURE unreachable_code IS2 x NUMBER := 10;3 BEGIN4 IF x = 10 THEN5 x := 20;6 ELSE7 x := 100; -- unreachable code8 END IF;9 END unreachable_code;10 / SP2-0804: Procedure created with compilation warnings SQL> show errErrors for PROCEDURE UNREACHABLE_CODE: LINE/COL ERROR-------- -------------------------------------7/7 PLW-06002: Unreachable code

plw*.sql

Page 35: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 35

Conditional Compilation in 10g Release 2

Compile selected parts of a program based on conditions you provide with various compiler directives. – The most significant new feature for PL/SQL developers.

Conditional compilation will allow you to:– Write code that will compile and run under different

versions of Oracle (relevant for future releases). – Run different code for test, debug and production phases.

That is, compile debug statements in and out of your code.

– Expose private modules for unit testing.

Page 36: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 36

Inquiry directive example

Set up conditional compilation of debugging and tracing with special "CC" flags that are placed into the compiler settings for a program.

ALTER SESSION SET PLSQL_CCFLAGS = 'oe_debug:true, oe_trace_level:10';

CREATE OR REPLACE PROCEDURE calculate_totalsISBEGIN$IF $$oe_debug AND $$oe_trace_level >= 5$THEN DBMS_OUTPUT.PUT_LINE ('Tracing at level 5 or higher');$END NULL;END calculate_totals;/

cc_debug_trace.sql

Page 37: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 37

DBMS_DB_VERSION

Each version of Oracle from Oracle Database 10g Release 2 will contain a DBMS_DB_VERSION package.– Contains a set of Boolean constants that tell you how this

version relates to other Oracle versions.– Here is an example:

This will be most beneficial when we can use it in multiple versions of Oracle!

$IF DBMS_DB_VERSION.VER_LE_10_2$THEN Use this code.$ELSEIF DBMS_DB_VERSION.VER_LE_11 This is a placeholder for future.$ENDIF

Page 38: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 38

Oracle11g In-lining optimization

When you set the optimization level to 3, the compiler will automatically "in-line" the code for any local modules for which the operation is specified.– A subprogram that is defined in the declaration section of

that program.

Oracle's own tests have shown 10-20% performance improvement.– Depends on many local modules you create and how

often they are used.

Note: compile code size increases.

11g

ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL = 3;

11g_inline.sql

Page 39: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 39

Inlining optimization, continued

Inlining must be explicitly required in your code with a new INLINE pragma.

Inlining applies to the following statements:– Assignment, CALL, conditional, CASE, CONTINUE-WHEN,

EXECUTE IMMEDIATE, EXIT-WHEN, LOOP, RETURN

You can also request inlining for all executions of the subprogram by placing the PRAGMA before the declaration of the subprogram.

Inlining, like NOCOPY, is a request.– Under some circumstances, inlining will not take place.

You can also explicitly turn off inlining by specifying "NO" in the PRAGMA.

11g

11g_inline.sql

Page 40: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 40

Compiler Improvements - Summary

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

Page 41: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 41

PL/SQL Collections

Collections are single-dimensioned lists of information, similar to 3GL arrays.

They are an invaluable data structure.– All PL/SQL developers should be very comfortable

with collections and use them often. Collections take some getting used to.

– They are not the most straightforward implementation of array-like structures.

– Advanced features like string indexes and multi-level collections can be a challenge.

Page 42: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 42

What we will cover on collections

Review of basic functionality Indexing collections by strings Working with collections of collections MULTISET operators for nested tables Then later in the section on high performance

PL/SQL:– Bulk processing with FORALL and BULK

COLLECT– Table functions and pipelined functions

Page 43: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 43

What is a collection?

A collection is an "ordered group of elements, all of the same type." (PL/SQL User Guide and Reference)– That's a very general definition; lists, sets, arrays and similar

data structures are all types of collections.– Each element of a collection may be addressed by a unique

subscript, usually an integer but in some cases also a string.– Collections are single-dimensional, but you can create

collections of collections to emulate multi-dimensional structures.

abc def sf q rrr swq...1 2 3 4 22 23

Page 44: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 44

Why use collections?

Generally, to manipulate in-program-memory lists of information. – Much faster than working through SQL.

Serve up complex datasets of information to non-PL/SQL host environments using table functions.

Dramatically improve multi-row querying, inserting, updating and deleting the contents of tables. – Combined with BULK COLLECT and FORALL....

Emulate bi-directional cursors, which are not yet supported within PL/SQL.

bidir.*

Page 45: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 45

Three Types of Collections

Associative arrays (aka index-by tables) – Can be used only in PL/SQL blocks.– Similar to hash tables in other languages, allows you to

access elements via arbitrary subscript values.

Nested tables and Varrays – Can be used in PL/SQL blocks, but also can be the

datatype of a column in a relational table. – Part of the object model in PL/SQL.– Required for some features, such as table functions– With Varrays, you specify a maximum number of elements

in the collection, at time of definition.

Page 46: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 46

About Associative Arrays

Unbounded, practically speaking. – Valid row numbers range from -2,147,483,647 to

2,147,483,647.

– This range allows you to employ the row number as an intelligent key, such as the primary key or unique index value, because AAs also are:

Sparse– Data does not have to be stored in consecutive rows, as is

required in traditional 3GL arrays and VARRAYs.

Index values can be integers or strings (Oracle9i R2 and above).

assoc_array_example.sql

Page 47: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 47

About Nested Tables

Name reflects fact that this collection can be "nested" inside relational table as a column.

Type can be defined at schema level.

No practical, pre-defined limit on a nested table.– Valid row numbers range from 1 to 2,147,483,647.

Part of object model, requiring initialization.

Is always dense initially, but can become sparse after deletes.

nested_table_example.sql

Page 48: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 48

About Varrays

Has a maximum size, associated with its type. – Can adjust the size at runtime in Oracle10g R2.

Part of object model, requiring initialization.

Is always dense; you can only remove elements from the end of a varray.

Can be defined as a schema level type and used as a relational table column type.

varray_example.sql

Page 49: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 49

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.

Page 50: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 50

Useful reminders for PL/SQL collections

Memory for collections comes out of the PGA or Process Global Area– One per session, so a program using collections can

consume a large amount of memory. Use the NOCOPY hint to reduce overhead of passing

collections in and out of program units. Encapsulate or hide details of collection management. Don't always fill collections sequentially. Think about

how you need to manipulate the contents. Try to read a row that doesn't exist, and Oracle raises

NO_DATA_FOUND.mysess.pkg

sess2.sqlnocopy*.*

Page 51: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 51

Apply PL/SQL Collections

We will take a look at the following application of PL/SQL collections:– Caching data in the PGA with collections

Then we will explore advanced features of collections.– String-indexed collections– Multi-level collections

Page 52: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 52

Data Caching with PL/SQL Collections

Manipulating memory is much more efficient than reading/writing hard drives.– That's the whole point of the SGA.

But not all memory is created (and managed) the same. So it would seem to make sense that...

Manipulating faster memory will be more efficient than manipulating slow memory.

PGA memory is faster than SGA memory. – Don't have to go through the SQL layer.– So how can we take advantage of this fact?

Page 53: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 53

Function

PGA

Data Caching with PL/SQL Collections

First access

Subsequent accesses

PGAFunction

Database/ SGA

Not in cache;Request datafrom database

Pass Datato Cache

Application

Application Requests Data

Data retrieved from cache Data returned

to application

Application

Application Requests Data

Data returned to application

Data retrieved from cache

Database/ SGA

Data found incache. Databaseis not needed.

emplu.pkgemplu.tst

Page 54: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 54

PGA Caching: Things to keep in mind

Must use package-level data so that it persists.– Memory is consumed by the PGA and so is multiplied for

all users of the application.

Cache cannot be shared across sessions.– Or at least not very easily/practically.– If using connection pooling, must think through the

consequences.

Useful under specific scenarios....– Small, static dataset– Single or small number of batch processes

syscache.pkg

Page 55: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 55

New indexing capabilities for associative arrays

Prior to Oracle9iR2, you could only index by BINARY_INTEGER.

You can now define the index on your associative array to be:– Any sub-type derived from BINARY_INTEGER– VARCHAR2(n), where n is between 1 and 32767– %TYPE against a database column that is consistent with

the above rules– A SUBTYPE against any of the above.

This means that you can now index on string values! (and concatenated indexes and...)

Oracle9i Release 2

Page 56: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 56

Examples of New TYPE Variants

All of the following are now valid TYPE declarations in Oracle9i Release 2– You cannot use %TYPE against an INTEGER column,

because INTEGER is not a subtype of BINARY_INTEGER.

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 NUMBER INDEX BY employee.last_name%TYPE; TYPE array_t8 IS TABLE OF NUMBER INDEX BY types_pkg.subtype_t;

Oracle9i Release 2

Page 57: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 57

Working with string-indexed collections

The syntax is exactly the same, but you should keep this in mind:– The datatype returned by FIRST, LAST, NEXT and PRIOR

methods is VARCHAR2.– The longer the string values, the more time it takes Oracle

to hash that string to the integer that is actually used as the index value.

If you are indexing by integer and find that your values are getting close to the limits (2**31 - 1 or -2**31 + 1), convert to a string index.

assoc_array*.sqlassoc_array_perf.tst

int_to_string_indexing.sql

Page 58: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 58

The String Tracker package (V1)

Another example: I need to keep track of the names of variables that I have already used in my test code generation.– Can't declare the same variable twice.CREATE OR REPLACE PACKAGE BODY string_tracker

IS TYPE used_aat IS TABLE OF BOOLEAN INDEX BY maxvarchar2_t; g_names_used used_aat;

FUNCTION string_in_use ( value_in IN maxvarchar2_t ) RETURN BOOLEAN IS BEGIN RETURN g_names_used.EXISTS ( value_in ); END string_in_use;

PROCEDURE mark_as_used (value_in IN maxvarchar2_t) IS BEGIN g_names_used ( value_in ) := TRUE; END mark_as_used;END string_tracker;

string_tracker1.*

Page 59: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 59

Rapid access to data via strings

One of the most powerful applications of string-indexed collections is to construct very fast pathways to static data from within PL/SQL programs. – If repeatedly querying the same data from the database,

why not cache it in your PGA inside collections?

Emulate the various indexing mechanisms (primary key, unique indexes) with collections.

Demonstration package:assoc_array5.sql

Comparison of performance of different approaches:

vocab*.*

Generate a caching package:genaa.sqlgenaa.tst

Page 60: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 60

Multi-level Collections

Prior to Oracle9i, you could have collections of records or objects, but only if all fields were scalars.– A collection containing another collection was not

allowed. Now you can create collections that contain

other collections and complex types.– Applies to all three types of collections.

The syntax is non-intuitive and resulting code can be quite complex.

Oracle9i

Page 61: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 61

String Tracker Version 2

The problem with String Tracker V1 is that it only supports a single list of strings.– What if I need to track multiple lists

simultaneously or nested?

Let's extend the first version to support multiple lists by using a string-indexed, multi-level collection.– A list of lists....

Page 62: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 62

The String Tracker package (V2)

CREATE OR REPLACE PACKAGE BODY string_trackerIS TYPE used_aat IS TABLE OF BOOLEAN INDEX BY maxvarchar2_t; TYPE list_of_lists_aat IS TABLE OF used_aat INDEX BY maxvarchar2_t; g_list_of_lists list_of_lists_aat;

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.*

Page 63: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 63

Other multi-level collection examples

Multi-level collections with intermediate records and objects.

Emulation of multi-dimensional arrays– No native support, but can creates nested

collections to get much the same effect.– Use the UTL_NLA package (10gR2) for complex

matrix manipulation. Four-level nested collection used to track

arguments for a program unit.– Automatically analyze ambiguous overloading.

multdim*.*

ambig_overloading.sqlOTN: OverloadCheck

multilevel_collections.sql

Page 64: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 64

Encapsulate these complex structures!

When working with multi-level collections, you can easily and rapidly arrive at completely unreadable and un-maintainable code.

What' s a developer to do?– Hide complexity -- and all data structures -- behind

small modules.– Work with and through functions to retrieve

contents and procedures to set contents.

cc_smartargs.pkb:cc_smartargs.next_overloading

cc_smartargs.add_new_parameter

Page 65: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 65

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..

You can now…– Check for equality and inequality– Perform UNION, INTERSECT and MINUS operations– Check for and remove duplicates

Only works with nested tables of scalars.

Oracle10g

Page 66: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 66

Check for equality and inequality

Just use the basic operators….and NULLs have the usual disruptive impact.

Oracle10g

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.sql10g_compare2.sql

10g_compare_old.sql

Page 67: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 67

UNION, INTERSECT, MINUS

Straightforward, with the MULTISET keyword.

Oracle10g

BEGIN our_favorites := my_favorites MULTISET UNION dad_favorites; our_favorites := my_favorites MULTISET UNION DISTINCT dad_favorites; our_favorites := my_favorites MULTISET INTERSECT dad_favorites; our_favorites := dad_favorites MULTISET EXCEPT my_favorites;END;

10g_setops.sql10g_string_nt.sql10g_favorites.sql

10g*union*.sql

SQL: UNION

SQL: UNION ALL

SQL: INTERSECT

SQL: MINUS

Page 68: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 68

Distinct sets of values

Use the SET operator to work with distinct values, and determine if you have a set of distinct values.

Oracle10g

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.sql10g_favorites.pkg

Page 69: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 69

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."

Page 70: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 70

Collections vs. Global Temporary Tables

Global temporary tables cut down on the overhead of working with persistent tables.– And you can use the full power of SQL, which is

their main advantage over collections.

GTTs still require interaction with the SGA. So collections will still be faster, but they will

use more memory.– GTTs consume SGA memory.

global_temp_tab_vs_coll.sql

Page 71: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 71

Collections: the latest frontier

Five-plus years ago, many programmers wrestled with making packages an every-day part of their PL/SQL coding.

Today I offer this challenge: learn collections thoroughly and apply them throughout your backend code.– Your code will get faster and in many cases

much simpler than it might have been (though not always!).

Hands-On Collection seminarwww.oracleplsqlprogramming.com/resources.html

Page 72: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 72

>> High Performance PL/SQL

We always want our programs to run faster. But remember the 80-20 rule:

– Most of your code will never be part of a bottleneck, so don't obsess about optimizing every line of code.

We will look in this section at...– Calculating elapsed time– Data caching options– Oracle11g features for performance– BULK COLLECT and FORALL– Other, less astounding, performance techniques

Page 73: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 73

Calculating Elapsed Time of Programs

Many options for analyzing Oracle performance: TKPROF, SET TIMING ON, etc.– But they usually don't offer the granularity I need for my

PL/SQL performance analysis. Oracle offers DBMS_UTILITY.GET_TIME and

GET_CPU_TIME (10g) to compute elapsed time down to the hundredth of a second. – Can also use SYSTIMESTAMP

DECLARE l_start_time PLS_INTEGER;BEGIN l_start_time := DBMS_UTILITY.get_time; -- Do stuff here! DBMS_OUTPUT.put_line (DBMS_UTILITY.get_time – l_start_time);END;

plvtmr.*tmr.ot

this_user*.*

Page 74: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 74

Data Caching Options

Why cache data?– Because it is static and therefore you want to

avoid the performance overhead of retrieving that data over and over again.

Options for caching data:– The SGA: Oracle does lots of caching for us, but

it is not always the most efficient means.– Package data structures (PGA)– Oracle11g Function Result Cache

Page 75: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 75

Packaged collection caching

Prior to Oracle 11g, the best caching option for PL/SQL programs involved declaring a package-level data structure.– It persists for the entire session.

Very fast and easy to define, but it has its drawbacks.– The cache is copied in every session connected to

Oracle. Significant impact on memory usage.– Very difficult to synchronize cache with changes to

underlying database tables.

emplu*.*

Page 76: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 76

The Oracle 11g Function Result Cache

Oracle offers a far superior solution in 11g: the Function Result Cache.

By applying a simple RESULT_CACHE clause to your function, Oracle will:– Cache the values returned by the function, along with the

input values.– Return the cached values if the same input values are

provided.– Share this cache among all sessions in the instance.– Invalidate the cache when changes are made to

dependent tables.

11g

Page 77: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 77

Function Result Cache Example

CREATE OR REPLACE PACKAGE emplu11gIS FUNCTION onerow (employee_id_in IN employees.employee_id%TYPE) RETURN employees%ROWTYPE RESULT_CACHE;END emplu11g;

CREATE OR REPLACE PACKAGE BODY emplu11gIS FUNCTION onerow (employee_id_in IN employees.employee_id%TYPE) RETURN employees%ROWTYPE RESULT_CACHE RELIES_ON (employees) IS onerow_rec employees%ROWTYPE; BEGIN SELECT * INTO onerow_rec FROM employees WHERE employee_id = employee_id_in;

RETURN onerow_rec; END onerow;END emplu11g;

11g_emplu*.*

The specification must indicate you are using a result cache.

The body specifies the "relines on" dependencies, if any.

Page 78: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 78

Tuning the Result Cache

Oracle offers a number of ways to manage the result cache and tune it to your specific application needs:

RESULT_CACHE_SIZE initialization parameter

DBMS_RESULT_CACHE management package

v$RESULT_CACHE_* performance views

11g

Page 79: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 79

Look for opportunities to cache!

Whether you are on 9i, 10g or 11g, you should always look for opportunities to cache.– Are there tables that are always static during

user sessions?– Are there tables that are queried much more

frequently than they are changed?

Apply the most appropriate technique, but don't leave the users waiting...

Page 80: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 80

Turbo-charge SQL with bulk processing statements

Improve the performance of multi-row SQL operations by an order of magnitude or more with bulk/array processing in PL/SQL!

CREATE OR REPLACE PROCEDURE upd_for_dept ( dept_in IN employee.department_id%TYPE ,newsal_in IN employee.salary%TYPE)IS CURSOR emp_cur IS SELECT employee_id,salary,hire_date FROM employee WHERE department_id = dept_in;BEGIN FOR rec IN emp_cur LOOP

adjust_compensation (rec, newsal_in);

UPDATE employee SET salary = rec.salary WHERE employee_id = rec.employee_id; END LOOP;END upd_for_dept;

Row by row processing: simple and elegant but inefficient

Page 81: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 81

Oracle server

PL/SQL Runtime Engine SQL Engine

PL/SQL blockProcedural statement executor

SQL statement executor

FOR rec IN emp_cur LOOP UPDATE employee SET salary = ... WHERE employee_id = rec.employee_id;END LOOP;

Performance penalty Performance penalty for many “context for many “context switches”switches”

Row by row processing of DML in PL/SQL

Page 82: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 82

Bulk processing with FORALLOracle server

PL/SQL Runtime Engine SQL Engine

PL/SQL blockProcedural statement executor

SQL statement executor

FORALL indx IN list_of_emps.FIRST.. list_of_emps.LAST UPDATE employee SET salary = ... WHERE employee_id = list_of_emps(indx);

Fewer context switches,Fewer context switches,same SQL behaviorsame SQL behavior

Update...

Update...

Update...

Update...

Update...

Update...

Update...

Update...

Update...

Update...

Update...

Update...

Page 83: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 83

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.

Page 84: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 84

Use BULK COLLECT INTO for Queries

DECLARE TYPE employees_aat IS TABLE OF employees%ROWTYPE INDEX BY BINARY_INTEGER;

l_employees employees_aat;BEGIN SELECT * BULK COLLECT INTO l_employees FROM employees; FOR indx IN 1 .. l_employees.COUNT LOOP process_employee (l_employees(indx)); END LOOP;END;

bulkcoll.sqlbulktiming.sql

Declare a collection of

records to hold the queried data.

Use BULK COLLECT to

retrieve all rows.

Iterate through the 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.

Page 85: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 85

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;

TYPE emp_tt IS TABLE OF emps_in_dept_cur%ROWTYPE; emps emp_tt;BEGIN OPEN emps_in_dept_cur; LOOP FETCH emps_in_dept_cur BULK COLLECT INTO emps LIMIT 1000;

EXIT WHEN emps.COUNT = 0;

process_emps (emps); END LOOP;END bulk_with_limit;

Use the LIMIT clause with the INTO to manage the amount of memory used with the BULK COLLECT operation.

Definitely the preferred approach in production applications with large or varying datasets.

bulklimit.sql

Page 86: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 86

Use the FORALL Bulk Bind Statement Instead of executing repetitive, individual DML statements, you

can write your code like this:

Things to be aware of:– You MUST know how to use collections to use this feature!– Only a single DML statement is allowed per FORALL.– New cursor attributes: SQL%BULK_ROWCOUNT returns number of

rows affected by each row in array. SQL%BULK_EXCEPTIONS...– Prior to Oracle10g, the binding array must be sequentially filled.– Use SAVE EXCEPTIONS to continue past errors.

PROCEDURE upd_for_dept (...) ISBEGIN FORALL indx IN list_of_emps.FIRST .. list_of_emps.LAST UPDATE employee SET salary = newsal_in WHERE employee_id = list_of_emps (indx);END;

bulktiming.sqlbulk_rowcount.sql

bulkexc.sql

Page 87: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 87

Better Exception Handlingfor Bulk Operations

Allows you to continue past errors and obtain error information for each individual operation (for dynamic and static SQL).

CREATE OR REPLACE PROCEDURE load_books (books_in IN book_obj_list_t)IS bulk_errors EXCEPTION; PRAGMA EXCEPTION_INIT ( bulk_errors, -24381 );BEGIN FORALL indx IN books_in.FIRST..books_in.LAST SAVE EXCEPTIONS INSERT INTO book values (books_in(indx));EXCEPTION WHEN BULK_ERRORS THEN FOR indx in 1..SQL%BULK_EXCEPTIONS.COUNT LOOP log_error (SQL%BULK_EXCEPTIONS(indx)); END LOOP;END;

Allows processing of all rows, even after an error

occurs.

New cursor attribute, a pseudo-

collection

bulkexc.sql

Oracle9i

Page 88: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 88

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

in behavior. dbms_errlog.*save_exc_vc_dbms_errlog.sql

cfl_to_bulk7.sql

Page 89: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 89

Bulk Processing Conclusions

Most important performance tuning feature in PL/SQL.– Almost always the fastest way to execute multi-row SQL

operations in PL/SQL. You trade off increased complexity of code for

dramatically faster execution.– But in Oracle Database 10g and above, the compiler will

automatically optimize cursor FOR loops to BULK COLLECT efficiency.

– No need to convert unless the loop contains DML. Watch out for the impact on PGA memory!

Page 90: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 90

The NOCOPY hint

By default, Oracle passes all arguments by value, not reference.– This means that OUT and IN OUT arguments

always involve some copying of data.

With NOCOPY, you turn off the copy process.– But it comes with a risk: Oracle will not

automatically "rollback" or reverse changes made to your variables if the NOCOPY-ed program raises an exception.

nocopy*.*string_nocopy.*

Page 91: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 91

The SIMPLE_INTEGER and real Native Compilation

Native Compilation– With PLSQL_CODE_TYPE='Native' ('INTERPRETED‘ is

the default), Oracle will compile PL/SQL code down to machine code on all chip sets supported by Oracle.

– Use only for production; you can’t debug native code.– Oracle recommends that you recompile your entire code

base (including STANDARD and built-in packages) using native compilation!

The new, faster SIMPLE_INTEGER:– Has a NOT NULL constraint– Values wrap, they do not overflow– Faster than PLS_INTEGER

11g

ALTER SESSION SET PLSQL_CODE_TYPE = 'NATIVE';

Page 92: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 92

>> Other Key and Useful Oracle11g Features

Trigger enhancements: define order and the compound trigger

Dynamic SQL interoperability and completeness Use sequences in native PL/SQL The CONTINUE statement Reference fields of records in FORALL PL/Scope Additional compile-time warnings

Page 93: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 93

The Compound Trigger

– Rather than manage multiple triggers on the same table, you can join all trigger operations into a single compound trigger.

– Avoidance of mutating trigger errors is now much simpler and more straightforward.

11g

CREATE TRIGGER full_mfe_excuse_transactionBEFORE UPDATE ON mfe_customersCOMPOUND TRIGGER ... declare variables here ...

BEFORE STATEMENT IS BEGIN ... END BEFORE STATEMENT;

BEFORE ROW IS BEGIN ... END BEFORE ROW;

AFTER ROW IS BEGIN ... END AFTER ROW;

AFTER STATEMENT IS BEGIN ... END AFTER STATEMENT;END full_mfe_excuse_transaction;

mutating.sql11g_compound_mutating.sql

Page 94: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 94

Specifying order of trigger firing

Prior to Oracle11g, when you defined more than one trigger on the same action (e.g., "before insert"), there was no guarantee of the order in which the triggers would fire.

Now simply include a FOLLOWS clause:CREATE OR REPLACE TRIGGER after_insert_validate BEFORE INSERT ON my_table FOR EACH ROW FOLLOWS after_insert_adjustBEGIN ...END;

11g

multiple_triggers.sqltrigger_conflict.sql

Page 95: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 95

Use sequences in native PL/SQL!

You no longer have to select from dual to get the next value of a sequence!– Much more intuitive code– Improvement in performance

CREATE OR REPLACE TRIGGER employees_bi_trg BEFORE INSERT ON employees FOR EACH ROWBEGIN :NEW.employee_id := my_seq.NEXTVAL;END;/

11g

11g_native_sequence.sql

Page 96: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 96

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;

11g

Page 97: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 97

Reference fields of records in FORALL

Prior to 11g, you could not reference a field of a record in FORALL.

SQL> DECLARE 2 TYPE two_columns_rt IS RECORD ( 3 employee_id employees.employee_id%TYPE 4 , salary employees.salary%TYPE 5 ); 6 TYPE id_name_list_tt IS TABLE OF two_columns_rt INDEX BY PLS_INTEGER; 7 l_list id_name_list_tt; 8 BEGIN 9 SELECT employee_id, salary 10 BULK COLLECT INTO l_list FROM employees; 11 12 FOR idx IN 1 .. l_list.COUNT LOOP 13 l_list (idx).salary := apply_cola (l_list (idx).salary); 14 END LOOP; 15 16 FORALL idx IN 1 .. l_list.COUNT 17 UPDATE employees SET salary = l_list (idx).salary 18 WHERE employee_id = l_list (idx).employee_id; 19 END; 20 / UPDATE employees SET salary = l_list (idx).salary *ERROR at line 17:PLS-00436: implementation restriction: cannot reference fields of BULK In-BIND

Instead, you have to break out the

data into separate collections.

Very irritating.

Oracle11g now lets you do this.

BUT...It is not

documented!

11g_field_of_record.sql

11g

Page 98: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 98

PL/Scope

A compiler-driven tool that collects information about identifiers and stores it in data dictionary views.

Use PL/Scope to answer questions like:– Where if a variable assigned a value in a program?– What variables are declared inside a given

program?– Which programs call another program (that is, you

can get down to a subprogram in a package)?– Find the type of a variable from its declaration.

11g

Page 99: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 99

PL/Scope examples

Enable gathering of PL/Scope data.ALTER SESSION SET plscope_settings='IDENTIFIERS:ALL'

Verify PL/Scope setting for a program.SELECT plscope_settings FROM user_plsql_object_settings WHERE NAME = 'PACK1' AND TYPE = 'PACKAGE BODY'

Identify all declarations for the specified set of programs whose names do not start with "L_".

SELECT name, signature, tyhpe FROM user_identifiers WHERE name NOT LIKE 'L\_%' ESCAPE '\' AND USAGE = 'DECLARATION' AND object_name LIKE '&1'

11g_plscope.sql

Page 100: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 100

New compile-time warnings

PLW-6009: Exception handler does not re-raise an exception.

PLW-7205: warning on mixed use of integer types– Namely, SIMPLE_INTEGER mixed with PLS_INTEGER

and BINARY_INTEGER PLW-7206: unnecessary assignments Lots of PRAGMA INLINE-related warnings More feedback on impact of optimization

– PLW-6007: Notification that entire subprograms were removed

plw*.sql files

Page 101: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 101

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!

Page 102: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 102

Dynamic SQL and dynamic PL/SQL

An overview of dynamic SQL Dynamic PL/SQL block execution Method 4 dynamic SQL When DBMS_SQL comes in handy...

– Parse very long strings– Describe columns in dynamic query– And method 4...

Oracle11g enhancements

Page 103: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 103

What is Dynamic SQL?

Dynamic SQL actually refers, in the world of PL/SQL, to two things:– SQL statements, such as a DELETE or CREATE

TABLE, that are constructed and executed at run-time.

– Anonymous PL/SQL blocks that are constructed, compiled and executed at run-time.

'DROP ' || l_type || ' ' || l_name

'BEGIN ' || l_proc_name || ' (' || l_parameters || '); END;'

Page 104: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 104

Some of the possibilities with Dynamic SQL

Build ad-hoc query and update applications.– The user decides what to do and see.

Execute DDL statements from within PL/SQL.– Not otherwise allowed in a PL/SQL block.

Soft-code your application logic, placing business rules in tables and executing them dynamically.– Usually implemented through dynamic PL/SQL

Page 105: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 105

Two Methods Available

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?

Page 106: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 106

NDS or DBMS_SQL: Which should you use?

Reasons to go with NDS:– Ease of use– Works with all SQL

datatypes (including user-defined object and collection types)

– Fetch into records and collections of records

– Usually faster runtime performance

Why You'd Use DBMS_SQL:– Method 4 Dynamic SQL– DESCRIBE columns of

cursor– SQL statements larger than

32K– Better reuse of parsed SQL

statements -- persistent cursor handles!

Bottom line: NDS should be your first choice.

tabcount.sftabcount81.sf

Page 107: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 107

Four Dynamic SQL Methods

Method 1: DDL or DML without bind variables– EXECUTE IMMEDIATE string

Method 2: DML with fixed number of bind variables– EXECUTE IMMEDIATE string USING

Method 3: Query with fixed number of expressions in the select list– EXECUTE IMMEDIATE string INTO

Method 4: Query with dynamic number of expressions in select list or DML with dynamic number of bind variables.– DBMS_SQL!

Page 108: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 108

Method 1: DDL within PL/SQL

Very easy, very dangerous with NDS.– Here's a procedure that "drops whatever".

CREATE OR REPLACE PROCEDURE drop_whatever (nm IN VARCHAR2) AUTHID CURRENT_USERIS CURSOR type_cur IS SELECT object_type FROM USER_OBJECTS WHERE object_name LIKE UPPER (nm); type_rec type_cur%ROWTYPE;BEGIN OPEN type_cur; FETCH type_cur INTO type_rec; IF type_cur%FOUND THEN EXECUTE IMMEDIATE 'DROP ' || type_rec.object_type || ' ' || nm; END IF;END;

dropwhatever.spcreind81.sphealth$.pkgsettrig.sp

Page 109: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 109

Method 2: DML (Update) with 2 bind variables

CREATE OR REPLACE PROCEDURE salary_raise ( raise_percent NUMBER, job VARCHAR2)IS TYPE loc_array_type IS TABLE OF offices.location%TYPE INDEX BY BINARY_INTEGER;

dml_str VARCHAR2 (200); loc_array loc_array_type;BEGIN SELECT location BULK COLLECT INTO loc_array FROM offices;

FOR i IN loc_array.FIRST .. loc_array.LAST LOOP dml_str := 'UPDATE emp_' || loc_array (i) || ' SET sal = sal * (1+(:XYZ/100))' || ' WHERE job = :123'; EXECUTE IMMEDIATE dml_str USING raise_percent, job; END LOOP;END;

Different table for

each location

Page 110: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 110

Method 3: COUNT(*) For Any Table

Here's a handy and simple utility based on NDS:

IF tabCount ('citizens', 'insured = ''NO''') > 40,000,000THEN DBMS_OUTPUT.PUT_LINE ( 'Not the best health care system in the world....');END IF;

tabcount81.sftabcount.sf

CREATE OR REPLACE FUNCTION tabCount ( tab IN VARCHAR2, whr IN VARCHAR2 := NULL, sch IN VARCHAR2 := NULL) RETURN INTEGERIS retval INTEGER;BEGIN EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || NVL (sch, USER) || '.' || tab || ' WHERE ' || NVL (whr, '1=1') INTO retval; RETURN retval;END;

Specify schema, table and WHERE clause...

Page 111: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 111

Quiz!

PROCEDURE process_lineitem ( line_in IN INTEGER)ISBEGIN IF line_in = 1 THEN process_line1; END IF;  IF line_in = 2 THEN process_line2; END IF;  ... IF line_in = 22045 THEN process_line22045; END IF;END;

What's wrong with this code?

How would you fix it?

Page 112: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 112

From 22,000 lines of code to 1!

Identify the pattern and resolve it either with reusable modules or dynamic abstractions.

PROCEDURE process_lineitem ( line_in IN INTEGER)ISBEGIN IF line_in = 1 THEN process_line1; END IF;  IF line_in = 2 THEN process_line2; END IF;  ... IF line_in = 22045 THEN process_line22045; END IF;END;

PROCEDURE process_lineitem ( line_in IN INTEGER)ISBEGIN EXECUTE IMMEDIATE 'BEGIN process_line'|| line_in ||'; END;';END;

dynplsql.txt

Page 113: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 113

Dynamic PL/SQL

Dynamically construct, compile and run an anonymous block with EXECUTE IMMEDIATE.– Begins with BEGIN or DECLARE.– Ends with END;. The trailing semi-colon is required;

otherwise it is parsed as an SQL statement. You can only reference globally-accessible data

structures (declared in a package specification). Exceptions can (and should) be trapped in the

block from which the dynamic PL/SQL was executed.

dynplsql8i.spdynplsql_nolocal.sql

Page 114: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 114

Dynamic PL/SQL Possibilities

There are so many possibilities....some things I have done:– Dramatically reduce code volume, improve performance.– Generic string parsing engine: parse any string into your own

collection.– Generic calculator engine.– Implement support for "indirect referencing": read and

change values of variables whose names are only determined at run-time.

And there are also dangers: SQL or code injection.dynvar.pkgdyncalc.pkg

str2list.*filepath*.pkg

Page 115: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 115

SQL (code) Injection

"Injection" means that unintended and often malicious code is inserted into a dynamic SQL statement.– Biggest risk occurs with dynamic PL/SQL, but it

is also possible to subvert SQL statements.

Best ways to avoid injection:– Restrict privileges tightly on user schemas.– Use bind variables whenever possible.– Check dynamic text for dangerous text.

code_injection.sqlsql_guard.*

Page 116: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 116

Method 4 Dynamic SQL with DBMS_SQL and NDS

Method 4 dynamic SQL is the most generalized and most complex - by far!– You don't know at compile time either the number of

columns or the number of bind variables.– With DBMS_SQL, you must put calls to

DBMS_SQL.DEFINE_COLUMN and/or DBMS_SQL.BIND_VARIABLE into loops.

With NDS, you must shift from dynamic SQL to dynamic PL/SQL.– How else can you have a variable INTO or USING

clause?

Page 117: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 117

Dynamic "SELECT * FROM <table>" in PL/SQL

You provide the table and WHERE clause. I display all the data.– I don't know in advance which or how many rows

to query. I can obtain the column information from

ALL_TAB_COLUMNS...and from there the fun begins!

You can do it with NDS, but you have to switch to dynamic PL/SQL and it is quite ugly. intab.sp

intab9i.spintab9i.tst

Page 118: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 118

Pseudo-code flow for DBMS_SQL implementation

BEGIN FOR each-column-in-table LOOP add-column-to-select-list; END LOOP;

DBMS_SQL.PARSE (cur, select_string, DBMS_SQL.NATIVE);

FOR each-column-in-table LOOP DBMS_SQL.DEFINE_COLUMN (cur, nth_col, datatype); END LOOP;

fdbk := DBMS_SQL.EXECUTE (cur); LOOP fetch-a-row; FOR each-column-in-table LOOP DBMS_SQL.COLUMN_VALUE (cur, nth_col, val); END LOOP; END LOOP;END;

Build the SELECT list

Define each column

Extract each value

Parse the variable SQL

Execute the query

Lots of code, but relatively straightforwardintab.sp

Page 119: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 119

Parsing very long strings

One problem with EXECUTE IMMEDIATE is that you pass it a single VARCHAR2 string. – Maximum length 32K.

So what do you do when your string is longer?– Very likely to happen when you are generating SQL

statements based on tables with many columns.– Also when you want to dynamically compile a

program.

Time to switch to DBMS_SQL!

Page 120: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 120

DBMS_SQL.PARSE overloading for collections

Oracle offers an overloading of DBMS_SQL.PARSE that accepts a collection of strings, rather than a single string.

DBMS_SQL offers two different array types:– DBMS_SQL.VARCHAR2S - each string max 255

bytes.– DBMS_SQL.VARCHAR2A - each string max

32,767 bytes (new in Oracle9i).

Page 121: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 121

Compile DDL from a file with DBMS_SQL

CREATE OR REPLACE PROCEDURE exec_ddl_from_file ( dir_in IN VARCHAR2 , file_in IN VARCHAR2)IS l_file UTL_FILE.file_type; l_lines DBMS_SQL.varchar2s; l_cur PLS_INTEGER := DBMS_SQL.open_cursor;

PROCEDURE read_file (lines_out IN OUT DBMS_SQL.varchar2s) IS BEGIN ... Read each line into array; see compile_from_file.sql l_file := UTL_FILE.fopen (dir_in, file_in, 'R'); END read_file;BEGIN read_file (l_lines); DBMS_SQL.parse (l_cur , l_lines , l_lines.FIRST , l_lines.LAST , TRUE , DBMS_SQL.native ); DBMS_SQL.close_cursor (l_cur); exec_ddl_from_file.sql

You can specify a subset of lines in

the array.

Page 122: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 122

Describe columns in a query

DBMS_SQL offers the ability to "ask" a cursor to describe the columns defined in that cursor.

By using the DESCRIBE_COLUMNS procedure, you can sometimes avoid complex parsing and analysis logic. – Particularly useful with method 4 dynamic SQL.

desccols.pkgdesccols.tst

Page 123: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 123

Dynamic SQL interoperability and completeness

EXECUTE IMMEDIATE and DBMS_SQL.PARSE now accept a CLOB.

Transform a cursor variable into a DBMS_SQL cursor, and vice versa.

DBMS_SQL bulk binds now work with your collection types and not just Oracle's.

Why? You can use DBMS_SQL when you need to handle very complex cases (dynamic SQL method 4), but then switch to cursor variables to make it easier to move data to program variables.

11g

Page 124: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 124

Dynamic SQL Interoperability Example

DECLARE l_query clob := 'SELECT ... '; l_cursor NUMBER := DBMS_SQL.open_cursor (); l_curvar sys_refcursor;

TYPE key_data_cur_t IS TABLE OF some_record_type;

l_key_data key_data_cur_t;BEGIN DBMS_SQL.parse (c => cur_num , language_flag => DBMS_SQL.native , STATEMENT => l_query ); DBMS_SQL.bind_variable (cur_num, ':d', department_id); DBMS_SQL.bind_variable (cur_num, ':s', salary); dummy := DBMS_SQL.EXECUTE (cur_num);

l_curvar := DBMS_SQL.to_refcursor (cur_num);

FETCH l_curvar BULK COLLECT INTO l_key_data;

CLOSE l_curvar;END;

Start with DBMS_SQL,

leveraging the flexibility of its low-level API.

Use cursor variables to

easily transfer data to the collection

11g

Page 125: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 125

The Wonder Of Table Functions

A table function is a function that you can call in the FROM clause of a query, and have it be treated as if it were a relational table.

Table functions allow you to perform arbitrarily complex transformations of data and then make that data available through a query.– Not everything can be done in SQL.

Combined with REF CURSORs, you can now more easily transfer data from within PL/SQL to host environments.– Java, for example, works very smoothly with cursor

variables

Page 126: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 126

Building a table function

A table function must return a nested table or varray based on a schema-defined type.– Types defined in a PL/SQL package can only be

used with pipelined table functions. The function header and the way it is called

must be SQL-compatible: all parameters use SQL types; no named notation.– In some cases (streaming and pipelined

functions), the IN parameter must be a cursor variable -- a query result set.

Page 127: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 127

Simple table function example

Return a list of names as a nested table, and then call that function in the FROM clause.

CREATE OR REPLACE FUNCTION lotsa_names ( base_name_in IN VARCHAR2, count_in IN INTEGER) RETURN names_ntIS retval names_nt := names_nt ();BEGIN retval.EXTEND (count_in);

FOR indx IN 1 .. count_in LOOP retval (indx) := base_name_in || ' ' || indx; END LOOP;

RETURN retval;END lotsa_names; tabfunc_scalar.sql

SELECT column_value FROM TABLE ( lotsa_names ('Steven' , 100)) names;

COLUMN_VALUE ------------Steven 1 ... Steven 100

Page 128: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 128

Streaming data with table functions

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.

CREATE TABLE stocktable ( ticker VARCHAR2(20), trade_date DATE, open_price NUMBER, close_price NUMBER)/CREATE TABLE tickertable ( ticker VARCHAR2(20), pricedate DATE, pricetype VARCHAR2(1), price NUMBER)/

tabfunc_streaming.sql

Page 129: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 129

Streaming data with table functions - 2

In this example, transform each row of the stocktable into two rows in the tickertable.

CREATE OR REPLACE PACKAGE refcur_pkgIS TYPE refcur_t IS REF CURSOR RETURN stocktable%ROWTYPE;END refcur_pkg;/

CREATE OR REPLACE FUNCTION stockpivot (dataset refcur_pkg.refcur_t) RETURN tickertypeset ...

BEGIN INSERT INTO tickertable SELECT * FROM TABLE (stockpivot (CURSOR (SELECT * FROM stocktable)));END;/

tabfunc_streaming.sql

Page 130: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 130

Use pipelined functions to enhance performance.

Pipelined functions allow you to return data iteratively, asynchronous to termination of the function.– As data is produced within the function, it is passed

back to the calling process/query.

Pipelined functions can only be called within a SQL statement.– They make no sense within non-multi-threaded PL/SQL

blocks.

CREATE FUNCTION StockPivot (p refcur_pkg.refcur_t) RETURN TickerTypeSet PIPELINED

Page 131: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 131

Applications for pipelined functions

Execution functions in parallel.– In Oracle9i Database Release 2 and above, use the

PARALLEL_ENABLE clause to allow your pipelined function to participate fully in a parallelized query.

– Critical in data warehouse applications. Improve speed of delivery of data to web

pages.– Use a pipelined function to "serve up" data to the

webpage and allow users to being viewing and browsing, even before the function has finished retrieving all of the data.

Page 132: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 132

Piping rows out from a pipelined function

CREATE FUNCTION stockpivot (p refcur_pkg.refcur_t) RETURN tickertypeset PIPELINED IS out_rec tickertype := tickertype (NULL, NULL, NULL); in_rec p%ROWTYPE;BEGIN LOOP FETCH p INTO in_rec; EXIT WHEN p%NOTFOUND; out_rec.ticker := in_rec.ticker; out_rec.pricetype := 'O'; out_rec.price := in_rec.openprice;

PIPE ROW (out_rec); END LOOP; CLOSE p;

RETURN;END;

tabfunc_setup.sqltabfunc_pipelined.sql

Add PIPELINED keyword to header

Pipe a row of data back to calling block

or query

RETURN...nothing at all!

Page 133: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 133

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).

{[ORDER | CLUSTER] BY column_list} PARALLEL_ENABLE ({PARTITION p BY [ANY | (HASH | RANGE) column_list]} )

Page 134: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 134

Table functions - Summary

Table functions offer significant new flexibility for PL/SQL developers.

Consider using them when you...– Need to pass back complex result sets of data

through the SQL layer (a query);– Want to call a user defined function inside a

query and execute it as part of a parallel query.

Page 135: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 135

>> Object-Oriented PL/SQL

Object Types and Object-Oriented Development

in PL/SQL

Page 136: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 136

Object Types in Oracle

An object type is similar to a package, but is Oracle's version of an O-O class.– Object type specification and body

Few development shops work with object types.– The initial implementation was weak, but it has gotten much

stronger (with support for inheritance, in particular).

Oracle uses object types in many of its new features (e.g., Oracle AQ, the XML datatype).– This has led more and more Oracle shops to take advantage

of this functionality.

Page 137: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 137

A Very Simple Object Type Example

The food type contains three attributes and no methods or programs.

Very similar to a CREATE TABLE statement– Big difference: an object type is not a "container"

for data.

– Instead, it is a "template" for instances of that type.

CREATE TYPE food_t AS OBJECT ( name VARCHAR2(100), food_group VARCHAR2 (100), grown_in VARCHAR2 (100));

Attributes

Page 138: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 138

Working with Simple Objects

DECLARE my_favorite_vegetable food_t := food_t ('Brussel Sprouts',

'VEGETABLE', 'Farm,Greenhouse,Backyard');BEGIN DBMS_OUTPUT.put_line ( my_favorite_vegetable.name);

my_favorite_vegetable.food_group := 'SATISFACTION';

IF INSTR ( my_favorite_vegetable.grown_in, 'yard') > 0 THEN order_seeds (my_favorite_vegetable); END IF;END;

Create a new object with a constructor.

Read an attribute value

Modify an attribute value

Pass an object as a parameter

objtype.sql

Page 139: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 139

"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.

Page 140: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 140

An Object Type with Methods

The timer object calculates elapsed time.

It consists of six attributes and all three types of methods.

CREATE TYPE tmr_t AS OBJECT ( starttime INTEGER , endtime INTEGER , startcputime INTEGER , endcputime INTEGER , repetitions INTEGER , NAME VARCHAR2 (2000)

, MEMBER PROCEDURE go , MEMBER PROCEDURE STOP (text IN VARCHAR2) , MEMBER FUNCTION timing RETURN INTEGER , MEMBER FUNCTION cputiming RETURN INTEGER , MEMBER FUNCTION timing_desc RETURN VARCHAR2 , STATIC FUNCTION make (name_in IN VARCHAR2) , CONSTRUCTOR FUNCTION tmr_t ( SELF IN OUT tmr_t , NAME IN VARCHAR2 , repetitions IN INTEGER ) RETURN SELF AS RESULT);

Attributes

Methods

tmr.otthisuser.*

Page 141: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 141

More on Constructor Functions

Always pass SELF as an IN OUT argument.– SELF is assumed for

member methods. Return SELF as

well. Populate SELF

inside the constructor.

CREATE TYPE tmr_t AS OBJECT (... CONSTRUCTOR FUNCTION tmr_t ( SELF IN OUT tmr_t,

name IN VARCHAR2, repetitions IN INTEGER ) RETURN SELF AS RESULT);

CREATE OR REPLACE TYPE BODY tmr_t AS CONSTRUCTOR FUNCTION tmr_t ( SELF IN OUT tmr_t,

name IN VARCHAR2, repetitions IN INTEGER ) RETURN SELF AS RESULT IS BEGIN SELf.repetitions := repetitions; SELF.name := name; RETURN; END;END;

Page 142: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 142

Support for inheritance in object types

You can now define a hierarchy of subtypes of object types.

A subtype contains all the attributes and methods of the parent type (or supertype).

The subtypes can also contain additional attributes and additional methods– Or it can override methods from the supertype.

You decide if an object type is INSTANTIABLE or is FINAL (cannot be extended to a subtype).– The default is FINAL.

Page 143: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 143

Let's Build a Type Hierarchy

We have a three level hierarchy:– food is the root type.– desserts are a type of food– cakes are a type of dessert.

We will make cake the most specialized type of food allowed in the hierarchy.

food

dessert

cake

"root",supertypeof dessert

subtype offood,supertypeof cake

subtypeof dessert

food.ot

Page 144: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 144

Creating a Simple Object Type Hierarchy

CREATE TYPE food_t AS OBJECT ( name VARCHAR2(100), food_group VARCHAR2 (100), grown_in VARCHAR2 (100)) NOT FINAL;

CREATE TYPE dessert_t UNDER food_t ( contains_chocolate CHAR(1), year_created NUMBER(4)) NOT FINAL;

CREATE TYPE cake_t UNDER dessert_t ( diameter NUMBER, inscription VARCHAR2(200));

NOT FINAL indicates that this type can be a supertype.

UNDER denotes that this type is a subtype.

An object instantiated from food_t has three attributes. A dessert object has five attributes. A cake has seven.

food.ot

Page 145: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 145

Substitutability of Object Types

A supertype is substitutable if one of its subtypes can substitute or stand in for it in a slot (a variable, column, etc.) whose declared type is the supertype.

Oracle supports object type substitution in columns of relational tables, attributes of object types and elements in collections.

"Any object of type cake is also a dessert, is also a food."

Page 146: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 146

Populate an Object Table

Create a table of objects of type food (root type).

Populate it with objects at different levels in hierarchy.DECLARE my_favorite_vegetables food_t := food_t ('Brussel Sprouts', 'VEGETABLE', 'farm' );BEGIN INSERT INTO sustenance VALUES (my_favorite_vegetables);

INSERT INTO sustenance VALUES (dessert_t ('Jello', 'PROTEIN', 'bowl', 'N', 1887 ) );

INSERT INTO sustenance VALUES (cake_t ( 'Marzepan Delight', 'CARBOHYDRATE', 'bakery', 'N', 1634, 8, 'Happy Birthday!' ) );END;

CREATE TABLE sustenance OF food_t;

Substitution of subtypes

Use of constructor to initialize a variable

food.ot

Page 147: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 147

Objects in a Collection

Create a table of objects of type food - root type.

DECLARE TYPE foodstuffs_nt IS TABLE OF food_t;

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' ) );BEGIN ...

Insert three different objects in the collection, each of a different type.

Declare a nested table

Page 148: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 148

Accessing Attributes in Substituted Types

You can substitute a subtype in a supertype column or attribute, but subtype-specific attributes and methods are by default not visible.

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

Page 149: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 149

Use TREAT to Identify Constrained Types

/* Show all the meals in which a main course is a dessert */SELECT * FROM meal WHERE TREAT (main_course AS dessert_t) IS NOT NULL;

/* Will fail, since main_course is of food_t type */SELECT main_course.contains_chocolate FROM meal WHERE TREAT (main_course AS dessert_t) IS NOT NULL;

/* Now works, since I am treating main_course as a dessert */SELECT TREAT (main_course AS dessert_t).contains_chocolate FROM meal WHERE TREAT (main_course AS dessert_t) IS NOT NULL; /* Set to NULL any desserts that are not cakes... */UPDATE meal SET dessert = TREAT (dessert AS cake_t);

treat.sql

Page 150: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 150

Turning Off Substitutability

Oracle provides syntax to turn off substitutability on either an entire type or specific attributes of a type.

CREATE TABLE brunches OF food_t NOT SUBSTITUTABLE AT ALL LEVELS;

CREATE TABLE meal ( served_on DATE, appetizer food_t, main_course food_t, dessert dessert_t ) COLUMN appetizer NOT SUBSTITUTABLE AT ALL LEVELS;

At the table level

For a single column

Page 151: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 151

Example: NOT SUBSTITUTABLE

The appetizer must be of type food_t; desserts are not acceptable.

SQL> BEGIN 2 INSERT INTO meal VALUES ( 3 SYSDATE + 1, 4 dessert_t ('Strawberries and cream', 5 'FRUIT', 'Backyard', 'N', 2001), 6 food_t ('Eggs benedict', 'PROTEIN', 'Farm'), 7 cake_t ('Apple Pie', 'FRUIT', 8 'Baker''s Square', 'N', 2001, 8, NULL)); 9 END; 10 /BEGIN*ERROR at line 1:ORA-00932: inconsistent datatypes

notsubst.sql

Page 152: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 152

Constraining Substitutability to a Specific Type

Suppose I want a column of desserts to contain only cakes?

CREATE TABLE meal ( served_on DATE, appetizer food_t, main_course food_t, dessert dessert_t ) COLUMN appetizer NOT SUBSTITUTABLE AT ALL LEVELS,

COLUMN dessert IS OF (ONLY cake_t) ;

Unconstrainednon-substitutability

Constrain to a single subtype

notsubst.sqlisof.sql

You can only constrain to a single type, not a list of types.

Page 153: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 153

Creating "Template" Types

Some object types should only be used as supertypes for other types; they are so general, you would not actually create and manipulate instances from those types.– Oracle allows you to define object types as NOT

INSTANTIABLE, as shown above.

CREATE TYPE Address_t AS OBJECT ( street VARCHAR2(1000), city VARCHAR2(30), ... ) NOT INSTANTIABLE NOT FINAL;

food2.ot

Page 154: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 154

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

Page 155: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 155

Overriding to Provide Specificity for Subtypes

Different calculations for desserts and cakes.

CREATE OR REPLACE TYPE BODY cake_t IS OVERRIDING MEMBER FUNCTION price RETURN NUMBER IS BEGIN RETURN ( 5.00

+ 0.25 * (LENGTH (SELF.inscription)) + 0.50 * diameter); END;END;

Generic dessert prices are determined by chocolate

content and age. Cake prices are driven by inscription length

and size..

food2.ot

CREATE OR REPLACE TYPE BODY dessert_tIS OVERRIDING MEMBER FUNCTION price RETURN NUMBER IS mult NUMBER := 1; BEGIN IF SELF.contains_chocolate = 'Y' THEN mult := 2; END IF; IF SELF.year_created < 1900 THEN mult := mult + 0.5; END IF; RETURN (10.00 * mult ); END;END;

Page 156: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 156

Disallowing Overrides

If you do not want a subtype to modify the behavior of a supertype method, declare it to be FINAL.– You can do this even in object types that are NOT

FINAL.

CREATE TYPE Person_t AS OBJECT ( ssn NUMBER, name VARCHAR2(30), address VARCHAR2(100), FINAL MEMBER PROCEDURE showInfo) NOT FINAL;

Page 157: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 157

Requiring Overrides to Methods

Suppose the implementation of a method changes with each subtype in the hierarchy and the supertype's implementation really is irrelevant.

Declare the method to be NOT INSTANTIABLE and then (a) you do not have to provide an implementation of the method and (b) all subtypes must provide an implementation.

CREATE TYPE food_t AS OBJECT ( name VARCHAR2(100), food_group VARCHAR2 (100), grown_in VARCHAR2 (100), NOT INSTANTIABLE MEMBER FUNCTION price RETURN NUMBER ) NOT FINAL NOT INSTANTIABLE;

If any member is NOT INSTANTIABLE, then the

entire type must be declared the same way.

food2.ot

Page 158: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 158

Oracle 11g: Referencing supertype methods

New to Oracle 11g, you can invoke a supertype's method in your override of that method. – Useful when you want to "add on" to supertype method,

but you certainly don't want to have to copy/paste the code needed.

One very typical example is when you want to "display" an object. – Show values of attributes of each type in the hierarchy.– Each "level" has its own "to _string" function.

11g

11g_gen_invoc.sql

Page 159: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 159

And then there is Dynamic Polymorphism

POLY-MORPHISM: multiple forms.– The ability to choose from multiple methods of the same name and

execute the appropriate method.

Static polymorphism– The decision about which method to execute is made at the time

the code is compiled. Static polymorphism is also known as overloading, and is supported in declaration sections of PL/SQL blocks.

Dynamic polymorphism – The decision about which method to execute is made at the time

the code is executed, at run-time. – This is also known as "dynamic method dispatch", and is available

for the first time in PL/SQL with support for object type inheritance.

Page 160: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 160

Exploring Dynamic Polymorphism

CREATE TYPE food_t AS OBJECT ( ...attributes... MEMBER FUNCTION price RETURN NUMBER ) NOT FINAL;

CREATE TYPE dessert_t UNDER food_t ( ...attributes... OVERRIDING MEMBER FUNCTION price RETURN NUMBER ) NOT FINAL) ; CREATE TYPE cake_t UNDER dessert_t ( ...attributes... -- No price method of its own. );

The food and dessert types each have a price method, but cake does not.

It simply inherits the dessert method.

Page 161: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 161

A Visual Representation

The root price function is over-ridden in the dessert subtype.

The cake subtype now simply inherits its price calculation from its dessert supertype.

food

dessert

cake

Price

Price

the "original"

An override

Inheritedcalculation

Page 162: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 162

Dynamically Choosing the Right Method

DECLARE TYPE foodstuffs_nt IS TABLE OF food_t;

fridge foodstuffs_nt := foodstuffs_nt ( food_t ('Eggs benedict', ...), dessert_t ('Strawberries and cream', ...), cake_t ('Chocolate Supreme', ...));BEGIN FOR indx IN fridge.FIRST .. fridge.LAST LOOP DBMS_OUTPUT.put_line ( 'Price of ' || fridge (indx).NAME || ' = ' || fridge (indx).price); END LOOP;END;

A collection of foods is populated with three

different object types.

The price invocation is resolved at run-time, and

not necessarily as the food_t.price method.

food3.otfood4.otfood5.ot

dynpoly_overhead.tst

Page 163: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 163

Other Object-Relational topics

Object tables The REF function and UTL_REF Object comparisons

– MAP and ORDER

Object views– INSTEAD OF triggers

Page 164: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 164

Object tables

You can create a table of objects, known as an object table.– Use special OF syntax to specify it.

Specify a primary key (from object attributes) or Oracle will create an object identifier, OID.– When the type does not have subtypes, you can use

conventional DML to change values of attributes.

Use the VALUE function to retrieve an object from the table.

CREATE TABLE food_table OF food_t

SELECT VALUE (f).name FROM food_table

object_table.sql

Page 165: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 165

The REF function

A REF is a logical pointer to a row in an object table.– The value itself of little interest: a long hex string.– The REF contains: the primary key or OID value; a

unique designator for the table; optionally, a ROWID.

You can use a REF to retrieve a row object without having to name the table!– That is, avoid the need for an explicit join to a table.

But no one is going to make you do this.

object_ref.sql

Page 166: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 166

The UTL_REF package UTL_REF allows you to manipulate objects through

its REF directly in PL/SQL.– You can lock, select, update or delete an object given only

its REF.CREATE OR REPLACE TYPE BODY subject_tAS MEMBER FUNCTION print_bt (str IN VARCHAR2) RETURN VARCHAR2 IS bt subject_t; BEGIN IF SELF.broader_term_ref IS NULL THEN RETURN str; ELSE UTL_REF.select_object (SELF.broader_term_ref, bt); RETURN bt.print_bt ( NVL (str, SELF.NAME)) || ' (' || bt.NAME || ')'; END IF; END;END; object_ref.sql

Page 167: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 167

UTL_REF programs

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.

Page 168: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 168

Comparing two objects

When objects are columns, you immediately run into the issue of how to compare them, sort them.

How is Oracle supposed to make sense of such statements as:

SELECT * FROM meals ORDER BY main_course;

DECLARE l_dinner food_t; l_dessert dessert_t;BEGIN IF l_dinner > l_dessert THEN ...

Page 169: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 169

Four options for comparisons

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.

Page 170: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 170

The MAP member method

Suppose I want food to be ordered as follows:– "First" - vegetables– "Last" - protein– "In between" - carbohydrates, fluids, etc.– Within a food group, a "tie" is broken based on the number of

characters in the name. Silly, I know.

CREATE OR REPLACE TYPE BODY food_t IS MAP MEMBER FUNCTION food_mapping RETURN NUMBER IS BEGIN RETURN ( CASE SELF.food_group WHEN 'PROTEIN' THEN 30000 WHEN 'LIQUID' THEN 20000 WHEN 'CARBOHYDRATE' THEN 15000 WHEN 'VEGETABLE' THEN 10000 END + LENGTH (SELF.NAME)); END;END;

map_example.sql

Page 171: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 171

The ORDER member method

An ORDER method accepts an object and compares it to SELF. It must return values as shown below:

For these semantics... ORDER must return...SELF < argumentObject Any negative number, usually -1

SELF = argumentObject 0

SELF > argumentObject Any positive number, usually 1

Undefined comparison NULL

So...you only need to write the appropriate code for your object type.

order_example.sql

Page 172: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 172

Object Views

An object view is a view "OF" object types, but whose defining query gathers data from relational tables.

If you have an existing relational design, but want to exploit O-O features on this data, create an object view on top of the relational data.

Will need to specify the object and the WITH OBJECT IDENTIFIER clause.

object_view.sql

Page 173: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 173

INSTEAD OF triggers

You cannot perform DML operations directly against the underlying relational tables through the object view.

Instead, create INSTEAD OF triggers that "intercept" the DML operation and transform it into something sensible.

CREATE OR REPLACE TRIGGER images_v_insertINSTEAD OF INSERT ON images_vFOR EACH ROWBEGIN /* Call a packaged procedure to perform the insert. */ manage_image.create_one ( :NEW.image_id, :NEW.file_type, :NEW.file_name, :NEW.bytes, :NEW.keywords);END;

Page 174: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 174

Helpful data dictionary views

USER_TYPES– All of the types in my schema, from object type to collection type.

USER_TYPE_ATTR – All of the attributes in my object types (similar to

USER_TAB_COLUMNS) USER_TYPE_METHODS

– All of the methods defined in my object types (similar to USER_PROCEDURES)

USER_OBJECT_TABLES– List of all object tables defined on specific relational tables– Note: object tables do not appear in USER_OBJECTS. Instead, you

must query from USER_ALL_TABLES USER_METHOD_RESULTS

– Gives you the datatype returned by methods in types

Page 175: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 175

Object Types Summary

They are finally becoming robust enough to be useful.

Object types are being used extensively by Oracle itself.– Advanced Queuing and XMLtype, among others.– This fact makes me more confident of the future,

performance, and capabilities of object types.

Get familiar with the syntax so that you can work with object types with confidence.

Page 176: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 176

Built-in package enhancements of note

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

Page 177: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 177

>> File IO in PL/SQL

UTL_FILE allows you to read from and write to operating system files on the database server.

Prior to Oracle9iR2, it was a fairly primitive utility, but Oracle9iR2 offers many enhancements.

– Remove, copy, rename files. Work with database directories.

Page 178: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 178

Authorizing Directory Access

With Oracle9iR2, you can read/write files in directories specified by...– The UTL_FILE_DIR parameter or...– Database directory objects

Oracle requires you to list explicitly those directories you wish to be able to read/write with UTL_FILE.– You do this by adding lines to the instance parameter file.

utl_file_dir = /tmputl_file_dir = /accounts/newdev

Page 179: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 179

Working with Database Directories

A Directory is a database "object", define with a CREATE statement.– You need CREATE ANY DIRECTORY privilege.

utlfile_92.sql

CREATE OR REPLACE DIRECTORY ERROR_LOG AS '/tmp/apps/log';

SELECT owner, directory_name, directory_path FROM ALL_DIRECTORIES;View those directories

to which you have access.

GRANT READ ON DIRECTORY error_log TO SCOTT;Grant READ or WRITE

privileges on a directory.

Page 180: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 180

Opening a File

Specify file location, name and operation type.– Types are 'R' for Read, 'W' for Write and 'A' for Append.– Specify maximum linesize (Default of 1024, maximum of 32767)

The FOPEN function returns a record ("file handle") based on the UTL_FILE.FILE_TYPE.– Contains three fields (ID, datatype and byte_mode).

Test to see if file is open with the IS_OPEN function.– In actuality, this function simply returns TRUE if the file handle's id

field is NOT NULL. Not much of a test...

DECLARE fid UTL_FILE.FILE_TYPE;BEGIN fid := UTL_FILE.FOPEN ('c:\temp', 'test.txt', 'W', max_linesize => 32767);END;

Page 181: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 181

Reading from a File

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 status flag.

DECLARE fid UTL_FILE.FILE_TYPE;BEGIN fid := UTL_FILE.FOPEN ('c:\temp', 'test.txt', 'R'); UTL_FILE.GET_LINE (fid, myline); UTL_FILE.FCLOSE (fid);END;

exec_ddl_from_file.sqlgetnext.sp infile.sf

Page 182: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 182

Writing to a File

You can use PUT, PUT_LINE or PUTF. – PUTF is like the C printf program, allowing for some

formatting.

Call FFLUSH to make sure that everything you have written to the buffer is flushed out to the 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;

create_file.spgenaa.sql

Page 183: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 183

Closing a File

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.

DECLARE fid UTL_FILE.FILE_TYPE;BEGIN fid := UTL_FILE.FOPEN ('c:\temp', 'test.txt', 'R'); UTL_FILE.GET_LINE (fid, myline); UTL_FILE.FCLOSE (fid);EXCEPTION WHEN UTL_FILE.READ_ERROR THEN UTL_FILE.FCLOSE (fid);END;

Page 184: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 184

Copy a File

You can specify an OS directory or a database object of type DIRECTORY (as shown above)

DECLARE file_suffix VARCHAR2 (100) := TO_CHAR (SYSDATE, 'YYYYMMDDHH24MISS');BEGIN -- Copy the entire file... UTL_FILE.fcopy ( src_location => 'DEVELOPMENT_DIR', src_filename => 'archive.zip', dest_location => 'ARCHIVE_DIR', dest_filename => 'archive' || file_suffix || '.zip' );END; fcopy.sql

fileIO92.pkg

Page 185: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 185

Remove a File

If no error is raised, then you deleted successfully

BEGIN UTL_FILE.fremove ( src_location => 'DEVELOPMENT_DIR', src_filename => 'archive.zip' );EXCEPTION -- If you call FREMOVE, you should check explicitly -- for deletion failures. WHEN UTL_FILE.delete_failed THEN ... Deal with failure to removeEND;

fremove.sqlfileIO92.pkg

Page 186: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 186

Rename/move a File

You specify target location and file nameDECLARE file_suffix VARCHAR2 (100) := TO_CHAR (SYSDATE, 'YYYYMMDD');BEGIN -- Rename/move the entire file in a single step. UTL_FILE.frename ( src_location => 'DEVELOPMENT_DIR', src_filename => 'archive.zip', dest_location => 'ARCHIVE_DIR', dest_filename => 'archive' || file_suffix || '.zip', overwrite => FALSE );EXCEPTION WHEN UTL_FILE.rename_failed THEN ... Deal with failure to renameEND;

frename.sqlfileIO92.pkg

Page 187: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 187

Obtaining attributes of a file

CREATE OR REPLACE FUNCTION flength ( location_in IN VARCHAR2, file_in IN VARCHAR2) RETURN PLS_INTEGERIS TYPE fgetattr_t IS RECORD ( fexists BOOLEAN, file_length PLS_INTEGER, block_size PLS_INTEGER );  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 ); RETURN fgetattr_rec.file_length;END flength;

How big is a file? What is its block size? Does the file exist?

All valuable questions. All answered with a call to

UTL_FILE.FGETATTR.

flength.sqlfileIO92.pkg

Page 188: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 188

Encapsulate and Improve

The best way to take advantage of the new UTL_FILE features is to encapsulate or wrap them inside a layer of enhancing code.– Improve the error handling and reporting.– Hide the messy details of workarounds/patches.– Provide easy backups of files.

Still lots of restrictions in UTL_FILE....– No higher-level file operations supported (change privileges,

create directory, get list of files in directory, random access to contents).

– Limitations on files you can access (no mapped files, no use of environmental variables).

– But don't worry....you can always use Java for that!

fileIO92.pkgfileIO92.tst

JFile.javaxfile.pkg

Page 189: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 189

DBMS_UTILITY.FORMAT_ERROR_BACKTRACE

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.

Long-standing challenge in PL/SQL:

How can I find the line number on which an error was raised in PL/SQL?

But in Oracle10g, we have "back trace"!

Page 190: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 190

Letting the error go unhandled…

CREATE OR REPLACE PROCEDURE proc1 ISBEGIN 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 ISBEGIN DBMS_OUTPUT.put_line ('calling proc2'); proc2;END;/

ERROR at line 1:ORA-01403: no data foundORA-06512: at "SCOTT.PROC1", line 7ORA-06512: at "SCOTT.PROC2", line 8ORA-06512: at "SCOTT.PROC3", line 5ORA-06512: at line 3

Backtrace.sql

Page 191: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 191

Displaying the “error stack” inside PL/SQL

CREATE OR REPLACE PROCEDURE proc3ISBEGIN DBMS_OUTPUT.put_line ('calling proc2'); proc2;EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.put_line ( DBMS_UTILITY.FORMAT_ERROR_STACK);END;/

SQL> exec proc3calling proc2calling proc1running proc1ORA-01403: no data foundbacktrace.sql

Page 192: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 192

Displaying the contents of BACKTRACE

CREATE OR REPLACE PROCEDURE proc3ISBEGIN 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 proc3calling proc2calling proc1running proc1Error stack at top level:ORA-06512: at "SCOTT.PROC1", line 5ORA-06512: at "SCOTT.PROC2", line 7ORA-06512: at "SCOTT.PROC3", line 5

backtrace.sqlbt.pkg

Page 193: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 193

DBMS_OUTPUT: relief in sight!

Oracle10g Release 2 offers some long-awaited enhancements...– DBMS_OUTPUT.PUT_LINE will now

accept and display strings up to 32K in length.

– You can set the buffer size to UNLIMITED.

SET SERVEROUTPUT ON SIZE UNLIMITED

32K!

Page 194: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 194

DBMS_RANDOM

Oracle makes it easy to generate random values. Two packages....– DBMS_RANDOM: good for many basic requirements– DBMS_CRYPTO_TOOLKIT: a more robust and complex

package for high-end security applications

DBMS_RANDOM subprograms– VALUE - return a number, either between 0 and 1, or

between specified low and high values– STRING - return a string of specified type and length

randomizer.*pick_winners_randomly.*

Page 195: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 195

UTL_RECOMP

The UTL_RECOMP built-in package offers two programs that you can use to recompile any invalid objects in your schema: RECOMP_SERIAL and RECOMP_PARALLEL. – Must connect as SYSDBA account to use

UTL_RECOMP.– Parallel version uses DBMS_JOB and will temporarily

disable all other jobs in the queue to avoid conflicts with the recompilation.

Oracle10g

CALL utl_recomp.recomp_serial ('SCOTT'); CALL utl_recomp.recomp_parallel ('SCOTT', 4); recompile.sql

Page 196: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 196

UTL_MAIL

UTL_MAIL makes it much easier to send email from within PL/SQL by hiding some of the complexities of UTL_SMTP.

To use UTL_MAIL...– Set the SMTP_OUTPUT_SERVER parameter.– Install the utlmail.sql and prvtmail.plb files under

SYS. That's right - it is not installed by default.– Grant EXECUTE on UTL_MAIL as desired.

Oracle10g

Page 197: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 197

Send an email message from PL/SQL

The interface to the SEND program mimics the basic "send email" form of Outlook and other email programs.

BEGIN /* Requires Oracle10g */ UTL_MAIL.send ( sender => '[email protected]' ,recipients => '[email protected], [email protected]' ,cc => '[email protected]' ,bcc => '[email protected]' ,subject => 'Cool new API for sending email' ,message =>'Hi Ya''ll,Sending email in PL/SQL is *much* easier with UTL_MAIL in 10g. Give it a try!Mailfully Yours,Bill' );END;

Page 198: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 198

Attachments and UTL_MAIL

You can attach RAW or VARCHAR2 content as an attachment (up to 32K).

BEGIN UTL_MAIL.send_attachment_raw ( sender => '[email protected]' ,recipients => '[email protected], [email protected]' ,cc => '[email protected]' ,bcc => '[email protected]' ,subject => 'Cool new API for sending email' ,message => '...' ,attachment => '...' /* Content of the attachment */ ,att_inline => TRUE /* Attachment in-line? */ ,att_filename => '...' /* Name of file to hold the attachment after the mail is received. */ );END;

Page 199: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 199

Acknowledgements and Resources

Very few of my ideas are truly original. I have learned from every one of these books and authors – and you can, too!

Page 200: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 200

A guide to my mentors/resources

A Timeless Way of Building – a beautiful and deeply spiritual book on architecture that changed the way many developers approach writing software.

On Intelligence – a truly astonishing book that lays out very concisely a new paradigm for understanding how our brains work.

Peopleware – a classic text on the human element behind writing software. Refactoring – formalized techniques for improving the internals of one's code

without affect its behavior. Code Complete – another classic programming book covering many aspects of

code construction. The Cult of Information – thought-provoking analysis of some of the down-

sides of our information age. Patterns of Software – a book that wrestles with the realities and problems with

code reuse and design patterns. Extreme Programming Explained – excellent introduction to XP. Code and Other Laws of Cyberspace – a groundbreaking book that recasts

the role of software developers as law-writers, and questions the direction that software is today taking us.

Page 201: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 201

Some Free PL/SQL Resources

http://www.oracle.com/technology/tech/pl_sql/index.html

http://www.oracle.com/technology/pub/columns/plsql/index.html

http://tahiti.oracle.com/

http://www.ToadWorld.com/SF

http://quest-pipelines.com/

http://quest-pipelines.com/pipelines/dba/PLVision/plvision.htm

Oracle Technology Network PL/SQL page

OTN Best Practice PL/SQL

Oracle documentation – complete, online, searchable!

PL/SQL Obsession - my on-line portal for PL/SQL developers

Quest Pipelines

I Love PL/SQL and...help improve the PL/SQL language!

PL/Vision

http://ILovePLSQLAnd.net

Page 202: 21st Century PLSQL with 11g

Copyright 2000-2007 Steven Feuerstein - Page 202

So Much to Learn...

Don't panic -- but don't stick your head in the sand, either.– You won't thrive as an Oracle7, Oracle8 or Oracle8i

developer!

You can do so much more from within PL/SQL than you ever could before.– Familiarity with new features will greatly ease the

challenges you face.