21st Century PLSQL with 11g

Published on July 2016 | Categories: Documents | Downloads: 79 | Comments: 0 | Views: 1182
of 202
Download PDF   Embed   Report

*Brought to you by WebandDB.com

Comments

Content

21st 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
Copyright 2000-2007 Steven Feuerstein - Page 1

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....
Copyright 2000-2007 Steven Feuerstein - Page 2

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.
Copyright 2000-2007 Steven Feuerstein - Page 3

Because I am a programmer obsessed...
And I build production applications....

So...why listen to me?

Copyright 2000-2007 Steven Feuerstein - Page 4

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?
Copyright 2000-2007 Steven Feuerstein - Page 5

How to benefit most from this session
 Watch, listen, focus on concepts and principles.  Download and use any of my the training materials: PL/SQL Obsession
http://www.ToadWorld.com/SF

 Download and use any of my scripts (examples, performance scripts, reusable code) from the same location: the demo.zip file. filename_from_demo_zip.sql  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!
Copyright 2000-2007 Steven Feuerstein - Page 6

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

Copyright 2000-2007 Steven Feuerstein - Page 7

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
Copyright 2000-2007 Steven Feuerstein - Page 8

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.
Copyright 2000-2007 Steven Feuerstein - Page 9

PL/SQL in Shared Memory
System Global Area (SGA) of RDBMS Instance
Shared Pool
Shared SQL Reserved Pool Pre-parsed
Select * from emp

Library cache
Update emp Set sal=...

Large Pool

calc_totals

show_emps

upd_salaries

Session 1

emp_rec emp%rowtype; tot_tab tottabtype;

emp_rec emp%rowtype; tot_tab tottabtype;

Session 1 memory (PGA/UGA)
Copyright 2000-2007 Steven Feuerstein - Page 10

Session 2 memory (PGA/UGA)

Session 2
mysess.pkg sess2.sql show_memory.sp

Execution Mode Options for PL/SQL  Review of definer rights  Introduction of invoker rights  A look at some of the nuances

Copyright 2000-2007 Steven Feuerstein - Page 11

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

Copyright 2000-2007 Steven Feuerstein - Page 12

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.
OE Code
Order_Mgt
Place Cancel

Sam_Sales
Close Old Orders

OE Data

X

Orders

Cannot alter table directly.

Note: Oracle built-in packages have long had the capability of running under the invoker's authority.
Copyright 2000-2007 Steven Feuerstein - Page 13

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!
Copyright 2000-2007 Steven Feuerstein - Page 14

Invoker Rights Syntax
 For top level modules:
CREATE [ OR REPLACE ] <module type> [ AUTHID { DEFINER | CURRENT_USER } ] AS ...

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

Copyright 2000-2007 Steven Feuerstein - Page 15

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

Central Code schema Central Code schema
PACKAGE acct_mgr
make
AUTHID CURRENT_USER

User/Data schema User/Data schema
PROCEDURE mng_account IS BEGIN ... code.acct_mgr.destroy(...); END;

modify destroy

...FROM accounts WHERE...

accounts table

Copyright 2000-2007 Steven Feuerstein - Page 16

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!
Copyright 2000-2007 Steven Feuerstein - Page 17

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 Copyright 2000-2007 Steven Feuerstein - Page 18

Compiling with "Template" Objects
 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.
Copyright 2000-2007 Steven Feuerstein - Page 19

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.sql invdefinv.tst irdynsql.sql invoker_rights_mode.sf
Copyright 2000-2007 Steven Feuerstein - Page 20

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
Copyright 2000-2007 Steven Feuerstein - Page 21

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;
Copyright 2000-2007 Steven Feuerstein - Page 22

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.
Copyright 2000-2007 Steven Feuerstein - Page 23

Logging with ATs
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;
logger.sp log81.pkg log81*.tst Copyright 2000-2007 Steven Feuerstein - Page 24 retry.pkg retry.tst

Avoid interdependencies with the main transaction.

Save on successful exit Don't forget to rollback on error!

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.
Copyright 2000-2007 Steven Feuerstein - Page 25

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.
Copyright 2000-2007 Steven Feuerstein - Page 26

autonserial.sql auton_in_sql.sql autontrigger*.sql

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.
Copyright 2000-2007 Steven Feuerstein - Page 27

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.

Copyright 2000-2007 Steven Feuerstein - Page 28

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

Copyright 2000-2007 Steven Feuerstein - Page 29

Oracle10g

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
Copyright 2000-2007 Steven Feuerstein - Page 30

Learn about the PL/SQL optimizer
http://www.oracle.com/technology/tech/pl_sql/htdocs/new_in_10gr1.htm

 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.
Copyright 2000-2007 Steven Feuerstein - Page 31

Optimizing compiler details
 Oracle retains optimizer settings on a module-by-module basis.
– When you recompile a particular module with non-default settings, the settings will "stick," allowing you to recompile later using REUSE SETTINGS. For example:
ALTER PROCEDURE bigproc COMPILE PLSQL_OPTIMIZE_LEVEL = 1;

 and then:
ALTER PROCEDURE bigproc COMPILE REUSE SETTINGS;

Copyright 2000-2007 Steven Feuerstein - Page 32

Oracle10g

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';
Copyright 2000-2007 Steven Feuerstein - Page 33

Compiler time warnings - example
 Check for “unreachable end” code….
SQL> CREATE OR REPLACE PROCEDURE unreachable_code IS 2 x NUMBER := 10; 3 BEGIN 4 IF x = 10 THEN 5 x := 20; 6 ELSE 7 x := 100; -- unreachable code 8 END IF; 9 END unreachable_code; 10 /   SP2-0804: Procedure created with compilation warnings   SQL> show err Errors for PROCEDURE UNREACHABLE_CODE:   LINE/COL ERROR -------- ------------------------------------7/7 PLW-06002: Unreachable code

plw*.sql

Copyright 2000-2007 Steven Feuerstein - Page 34

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.

Copyright 2000-2007 Steven Feuerstein - Page 35

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_totals IS BEGIN $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
Copyright 2000-2007 Steven Feuerstein - Page 36

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:
$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

 This will be most beneficial when we can use it in multiple versions of Oracle!
Copyright 2000-2007 Steven Feuerstein - Page 37

11g

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

ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL = 3;
Copyright 2000-2007 Steven Feuerstein - Page 38

11g

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_inline.sql
Copyright 2000-2007 Steven Feuerstein - Page 39

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
Copyright 2000-2007 Steven Feuerstein - Page 40

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 multilevel collections can be a challenge.
Copyright 2000-2007 Steven Feuerstein - Page 41

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
Copyright 2000-2007 Steven Feuerstein - Page 42

What is a collection?
1 abc 2 def 3 sf 4 q

...

22 rrr

23 swq

 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.
Copyright 2000-2007 Steven Feuerstein - Page 43

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 nonPL/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.*
Copyright 2000-2007 Steven Feuerstein - Page 44

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.
Copyright 2000-2007 Steven Feuerstein - Page 45

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
Copyright 2000-2007 Steven Feuerstein - Page 46

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
Copyright 2000-2007 Steven Feuerstein - Page 47

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
Copyright 2000-2007 Steven Feuerstein - Page 48

Wide Variety of Collection Methods
 Obtain information about the collection
COUNT returns number of rows currently defined in collection. EXISTS returns TRUE if the specified row is defined. FIRST/LAST return lowest/highest numbers of defined rows. NEXT/PRIOR return the closest defined row after/before the specified row. – LIMIT tells you the max. number of elements allowed in a VARRAY. – – – –

 Modify the contents of the collection
– DELETE deletes one or more rows from the index-by table. – EXTEND adds rows to a nested table or VARRAY. – TRIM removes rows from a VARRAY.

Copyright 2000-2007 Steven Feuerstein - Page 49

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.
Copyright 2000-2007 Steven Feuerstein - Page 50

mysess.pkg sess2.sql nocopy*.*

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

Copyright 2000-2007 Steven Feuerstein - Page 51

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?
Copyright 2000-2007 Steven Feuerstein - Page 52

Data Caching with PL/SQL Collections
First access
Database / SGA
Not in cache; Request data from database Pass Data to Cache Data retrieved from cache Data returned to application

Function

Application

PGA
Application Requests Data

Subsequent accesses
Database / SGA
Data found in cache. Database is not needed.

Data retrieved from cache

Data returned to application

Function

Application

PGA
Application Requests Data Copyright 2000-2007 Steven Feuerstein - Page 53

emplu.pkg emplu.tst

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
Copyright 2000-2007 Steven Feuerstein - Page 54

Oracle9i Release 2

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...)
Copyright 2000-2007 Steven Feuerstein - Page 55

Oracle9i Release 2

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 TYPE TYPE TYPE TYPE TYPE TYPE INDEX BY BINARY_INTEGER; INDEX BY PLS_INTEGER; INDEX BY POSITIVE; INDEX BY NATURAL; INDEX BY VARCHAR2(64); INDEX BY VARCHAR2(32767); INDEX BY employee.last_name%TYPE; TYPE array_t8 IS TABLE OF NUMBER INDEX BY types_pkg.subtype_t; array_t1 array_t2 array_t3 array_t4 array_t5 array_t6 array_t7 IS IS IS IS IS IS IS TABLE TABLE TABLE TABLE TABLE TABLE TABLE OF OF OF OF OF OF OF NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER

Copyright 2000-2007 Steven Feuerstein - Page 56

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*.sql assoc_array_perf.tst int_to_string_indexing.sql
Copyright 2000-2007 Steven Feuerstein - Page 57

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.
CREATE OR REPLACE PACKAGE BODY string_tracker IS TYPE used_aat IS TABLE OF BOOLEAN INDEX BY maxvarchar2_t; g_names_used used_aat;

– Can't declare the same variable twice.
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;
Copyright 2000-2007 Steven Feuerstein - Page 58

string_tracker1.*

Rapid access to data via strings
 One of the most powerful applications of stringindexed 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 Generate a caching package: genaa.sql genaa.tst Comparison of performance of different approaches: vocab*.*

Copyright 2000-2007 Steven Feuerstein - Page 59

Oracle9i

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.
Copyright 2000-2007 Steven Feuerstein - Page 60

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, multilevel collection.
– A list of lists....

Copyright 2000-2007 Steven Feuerstein - Page 61

The String Tracker package (V2)
CREATE OR REPLACE PACKAGE BODY string_tracker IS 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.*
Copyright 2000-2007 Steven Feuerstein - Page 62

Other multi-level collection examples
 Multi-level collections with intermediate records and objects. multilevel_collections.sql  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. multdim*.*

 Four-level nested collection used to track arguments for a program unit.
– Automatically analyze ambiguous overloading.
ambig_overloading.sql OTN: OverloadCheck
Copyright 2000-2007 Steven Feuerstein - Page 63

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
Copyright 2000-2007 Steven Feuerstein - Page 64

Oracle10g

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.
Copyright 2000-2007 Steven Feuerstein - Page 65

Oracle10g

Check for equality and inequality

 Just use the basic operators….and NULLs have the usual disruptive impact.
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;
Copyright 2000-2007 Steven Feuerstein - Page 66

10g_compare.sql 10g_compare2.sql 10g_compare_old.sql

Oracle10g

UNION, INTERSECT, MINUS

 Straightforward, with the MULTISET keyword.
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;
SQL: UNION ALL

SQL: UNION

SQL: INTERSECT

SQL: MINUS

Copyright 2000-2007 Steven Feuerstein - Page 67

10g_setops.sql 10g_string_nt.sql 10g_favorites.sql 10g*union*.sql

Oracle10g

Distinct sets of values

 Use the SET operator to work with distinct values, and determine if you have a set of distinct values.
DECLARE keep_it_simple strings_nt := strings_nt (); BEGIN keep_it_simple := SET (favorites_pkg.my_favorites); favorites_pkg.show_favorites ('FULL SET', favorites_pkg.my_favorites); p.l (favorites_pkg.my_favorites IS A SET, 'My favorites distinct?'); p.l (favorites_pkg.my_favorites IS NOT A SET, 'My favorites NOT distinct?'); favorites_pkg.show_favorites ( 'DISTINCT SET', keep_it_simple); p.l (keep_it_simple IS A SET, 'Keep_it_simple distinct?'); p.l (keep_it_simple IS NOT A SET, 'Keep_it_simple NOT distinct?'); END; 10g_set.sql 10g_favorites.pkg

Copyright 2000-2007 Steven Feuerstein - Page 68

How to choose your collection type
 Use associative arrays when you need to...
– Work within PL/SQL code only – Sparsely fill and manipulate the collection – Take advantage of negative index values and string indexing

 Use nested tables when you need to...
– Access the collection inside SQL – Want to perform set operations

 Use varrays when you need to...
– If you need to (or can) specify a maximum size to your collection – Access the collection inside SQL: better performance than nested tables, since varrays are stored "in line."
Copyright 2000-2007 Steven Feuerstein - Page 69

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
Copyright 2000-2007 Steven Feuerstein - Page 70

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 seminar www.oracleplsqlprogramming.com/resources.html
Copyright 2000-2007 Steven Feuerstein - Page 71

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

Copyright 2000-2007 Steven Feuerstein - Page 72

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;
Copyright 2000-2007 Steven Feuerstein - Page 73

plvtmr.* tmr.ot this_user*.*

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
Copyright 2000-2007 Steven Feuerstein - Page 74

Packaged collection caching
 Prior to Oracle 11g, the best caching option for PL/SQL programs involved declaring a packagelevel 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*.*
Copyright 2000-2007 Steven Feuerstein - Page 75

11g

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.
Copyright 2000-2007 Steven Feuerstein - Page 76

Function Result Cache Example
CREATE OR REPLACE PACKAGE emplu11g IS FUNCTION onerow (employee_id_in IN employees.employee_id%TYPE) RETURN employees%ROWTYPE RESULT_CACHE; END emplu11g; CREATE OR REPLACE PACKAGE BODY emplu11g IS FUNCTION onerow (employee_id_in IN employees.employee_id%TYPE) RETURN employees%ROWTYPE RESULT_CACHE RELIES_ON (employees) IS The specification must indicate you onerow_rec employees%ROWTYPE; are using a result cache. BEGIN SELECT * INTO onerow_rec FROM employees The body specifies the "relines on" WHERE employee_id = employee_id_in; dependencies, if any. RETURN onerow_rec; END onerow; END emplu11g;
11g_emplu*.*
Copyright 2000-2007 Steven Feuerstein - Page 77

11g

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
Copyright 2000-2007 Steven Feuerstein - Page 78

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...
Copyright 2000-2007 Steven Feuerstein - Page 79

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;
Copyright 2000-2007 Steven Feuerstein - Page 80

Row by row processing: simple and elegant but inefficient

Row by row processing of DML in PL/SQL
Oracle server
PL/SQL Runtime Engine
PL/SQL block
FOR rec IN emp_cur LOOP UPDATE employee SET salary = ... WHERE employee_id = rec.employee_id; END LOOP;

SQL Engine

Procedural statement executor

SQL statement executor

Performance penalty for many “context switches”
Copyright 2000-2007 Steven Feuerstein - Page 81

Bulk processing with FORALL
Oracle server
PL/SQL Runtime Engine
PL/SQL block
FORALL indx IN list_of_emps.FIRST.. list_of_emps.LAST UPDATE employee SET salary = ... WHERE employee_id = list_of_emps(indx); Update... Update... Update... Update... Update... Update...

SQL Engine

Procedural statement executor

SQL statement executor
Update... Update... Update... Update... Update... Update...

Fewer context switches, same SQL behavior

Copyright 2000-2007 Steven Feuerstein - Page 82

Bulk Processing in PL/SQL
 FORALL
– Use with inserts, updates and deletes. – Move data from collections to tables.

 BULK COLLECT
– Use with implicit and explicit queries. – Move data from tables into collections.

 In both cases, the "back back" end processing in the SQL engine is unchanged.
– Same transaction and rollback segment management – Same number of individual SQL statements will be executed. – But BEFORE and AFTER statement-level triggers only fire once per FORALL statement.
Copyright 2000-2007 Steven Feuerstein - Page 83

Use BULK COLLECT INTO for Queries
Declare a collection of records to hold the queried data. Use BULK COLLECT to retrieve all rows.
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.sql bulktiming.sql

Iterate through the collection contents with a loop.

Copyright 2000-2007 Steven Feuerstein - Page 84

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.

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; Use the LIMIT clause with the LOOP INTO to manage the amount of FETCH emps_in_dept_cur memory used with the BULK BULK COLLECT INTO emps LIMIT 1000; COLLECT operation. EXIT WHEN emps.COUNT = 0; process_emps (emps); END LOOP; END bulk_with_limit;
Copyright 2000-2007 Steven Feuerstein - Page 85

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

Use the FORALL Bulk Bind Statement
 Instead of executing repetitive, individual DML statements, you can write your code like this:
PROCEDURE upd_for_dept (...) IS BEGIN 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;

 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. bulktiming.sql
Copyright 2000-2007 Steven Feuerstein - Page 86

bulk_rowcount.sql bulkexc.sql

Oracle9i

Better Exception Handling for 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 Allows processing of all SAVE EXCEPTIONS rows, even after an error INSERT INTO book values (books_in(indx)); occurs. EXCEPTION WHEN BULK_ERRORS THEN FOR indx in 1..SQL%BULK_EXCEPTIONS.COUNT New cursor LOOP attribute, a pseudolog_error (SQL%BULK_EXCEPTIONS(indx)); END LOOP; collection END;
bulkexc.sql

Copyright 2000-2007 Steven Feuerstein - Page 87

DBMS_ERRLOG (Oracle10gR2)
 Allows DML statements to execute against all rows, even if an error occurs.
– The LOG ERRORS clause specifies how logging should occur. – Use the DBMS_ERRLOG package to associate a log table with DML operations on a base table.

 Much faster than trapping errors, logging, and then continuing/recovering.  You should consider using LOG ERRORS with FORALL (instead of SAVE EXCEPTIONS) so that you can obtain all error information!
– But there are some differences in behavior.
Copyright 2000-2007 Steven Feuerstein - Page 88

dbms_errlog.* save_exc_vc_dbms_errlog.sql cfl_to_bulk7.sql

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!

Copyright 2000-2007 Steven Feuerstein - Page 89

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.*
Copyright 2000-2007 Steven Feuerstein - Page 90

11g
 Native Compilation

The SIMPLE_INTEGER and real 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
ALTER SESSION SET PLSQL_CODE_TYPE = 'NATIVE';
Copyright 2000-2007 Steven Feuerstein - Page 91

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

Copyright 2000-2007 Steven Feuerstein - Page 92

11g
– 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.

The Compound Trigger
CREATE TRIGGER full_mfe_excuse_transaction BEFORE UPDATE ON mfe_customers COMPOUND 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.sql 11g_compound_mutating.sql
Copyright 2000-2007 Steven Feuerstein - Page 93

11g

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_adjust BEGIN ... END;
multiple_triggers.sql trigger_conflict.sql
Copyright 2000-2007 Steven Feuerstein - Page 94

11g

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 ROW BEGIN :NEW.employee_id := my_seq.NEXTVAL; END; /

Copyright 2000-2007 Steven Feuerstein - Page 95

11g_native_sequence.sql

11g

Using CONTINUE in a loop

 You can now tell PL/SQL to terminate execution of the current loop body and immediately go on to the next iteration of that loop.
BEGIN <<outer_loop >> FOR o_index IN 1 .. my_list.COUNT LOOP <<inner_loop>> FOR i_index IN your_list.FIRST .. your_list.LAST LOOP ... lots of code /* Skip the rest of this and the outer loop if condition is met. */ CONTINUE outer_loop WHEN condition_is_met; ... more inner loop logic END LOOP inner_loop; ... more outer loop logic END LOOP outer_loop; END;

Copyright 2000-2007 Steven Feuerstein - Page 96

11g

Reference fields of records in FORALL

 Prior to 11g, you could not reference a field of a record in FORALL. Instead, you have
SQL> 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

DECLARE to break out the TYPE two_columns_rt IS RECORD ( employee_id employees.employee_id%TYPE data into separate , salary employees.salary%TYPE collections. ); TYPE id_name_list_tt IS TABLE OF two_columns_rt INDEX BY PLS_INTEGER; l_list id_name_list_tt; Very irritating. BEGIN SELECT employee_id, salary BULK COLLECT INTO l_list FROM employees; FOR idx IN 1 .. l_list.COUNT LOOP l_list (idx).salary := apply_cola (l_list (idx).salary); END LOOP;

FORALL idx IN 1 .. l_list.COUNT UPDATE employees SET salary = l_list (idx).salary WHERE employee_id = l_list (idx).employee_id; END; / 11g_field_of_record.sql UPDATE employees SET salary = l_list (idx).salary * ERROR at line 17: PLS-00436: implementation restriction: cannot reference fields of BULK In-BIND Copyright 2000-2007 Steven Feuerstein - Page 97

Oracle11g now lets you do this. BUT... It is not documented!

11g

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.
Copyright 2000-2007 Steven Feuerstein - Page 98

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 FROM WHERE AND

name, signature, tyhpe user_identifiers name NOT LIKE 'L\_%' ESCAPE '\' AND USAGE = 'DECLARATION' object_name LIKE '&1'
11g_plscope.sql

Copyright 2000-2007 Steven Feuerstein - Page 99

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
Copyright 2000-2007 Steven Feuerstein - Page 100

Oracle11g PL/SQL: Easier to use, faster to execute, expanded capabilities
 Function result cache a very elegant solution to static data querying  PL/Scope offers wonderful new analytical capabilities on our code base  Fewer gaps in functionality
– Dynamic SQL interoperability, CONTINUE, FOLLOWS for triggers, etc.

 Now all we have to do is convince our management to upgrade to Oracle11g!

Copyright 2000-2007 Steven Feuerstein - Page 101

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
Copyright 2000-2007 Steven Feuerstein - Page 102

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 runtime. – 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;'

Copyright 2000-2007 Steven Feuerstein - Page 103

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

Copyright 2000-2007 Steven Feuerstein - Page 104

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?
Copyright 2000-2007 Steven Feuerstein - Page 105

tabcount.sf tabcount81.sf

NDS or DBMS_SQL: Which should you use?
 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!

 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

Bottom line: NDS should be your first choice.
Copyright 2000-2007 Steven Feuerstein - Page 106

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!
Copyright 2000-2007 Steven Feuerstein - Page 107

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_USER IS CURSOR type_cur IS SELECT object_type FROM USER_OBJECTS WHERE object_name LIKE UPPER (nm); type_rec type_cur%ROWTYPE; dropwhatever.sp creind81.sp BEGIN health$.pkg OPEN type_cur; FETCH type_cur INTO type_rec; settrig.sp IF type_cur%FOUND THEN EXECUTE IMMEDIATE 'DROP ' || type_rec.object_type || ' ' || nm; END IF; END;
Copyright 2000-2007 Steven Feuerstein - Page 108

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;
Copyright 2000-2007 Steven Feuerstein - Page 109

Different table for each location

Method 3: COUNT(*) For Any Table
 Here's a handy and simple ( CREATE OR REPLACE FUNCTION tabCount utility based on NDS: tab IN VARCHAR2, whr IN VARCHAR2 := NULL, sch IN VARCHAR2 := NULL) RETURN INTEGER IS Specify schema, table and retval INTEGER; WHERE clause... BEGIN EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || NVL (sch, USER) || '.' || tab || ' WHERE ' || NVL (whr, '1=1') INTO retval; RETURN retval; END;
IF tabCount ('citizens', 'insured = ''NO''') > 40,000,000 THEN DBMS_OUTPUT.PUT_LINE ( 'Not the best health care system in the world....'); END IF;
tabcount81.sf tabcount.sf
Copyright 2000-2007 Steven Feuerstein - Page 110

Quiz!
 What's wrong with this code?  How would you fix it?
PROCEDURE process_lineitem ( line_in IN INTEGER) IS BEGIN 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;

Copyright 2000-2007 Steven Feuerstein - Page 111

From 22,000 lines of code to 1!
PROCEDURE process_lineitem ( line_in IN INTEGER) IS BEGIN 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) IS BEGIN EXECUTE IMMEDIATE 'BEGIN process_line'|| line_in ||'; END;'; END;

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

Copyright 2000-2007 Steven Feuerstein - Page 112

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.sp
dynplsql_nolocal.sql
Copyright 2000-2007 Steven Feuerstein - Page 113

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.
Copyright 2000-2007 Steven Feuerstein - Page 114

dynvar.pkg dyncalc.pkg str2list.* filepath*.pkg

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.sql sql_guard.*
Copyright 2000-2007 Steven Feuerstein - Page 115

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?
Copyright 2000-2007 Steven Feuerstein - Page 116

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.sp intab9i.tst
Copyright 2000-2007 Steven Feuerstein - Page 117

Pseudo-code flow for DBMS_SQL implementation
Build the SELECT list Parse the variable SQL Define each column Execute the query Extract each value 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; Lots of code, but relatively END; intab.sp straightforward

Copyright 2000-2007 Steven Feuerstein - Page 118

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!
Copyright 2000-2007 Steven Feuerstein - Page 119

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

Copyright 2000-2007 Steven Feuerstein - Page 120

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 ); exec_ddl_from_file.sql DBMS_SQL.close_cursor (l_cur);

You can specify a subset of lines in the array.

Copyright 2000-2007 Steven Feuerstein - Page 121

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.pkg desccols.tst

Copyright 2000-2007 Steven Feuerstein - Page 122

11g 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.
Copyright 2000-2007 Steven Feuerstein - Page 123

11g

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

TYPE key_data_cur_t IS TABLE OF some_record_type;

Start with DBMS_SQL, leveraging the flexibility of its low-level API.

Use cursor variables to easily transfer data to the collection

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;

Copyright 2000-2007 Steven Feuerstein - Page 124

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
Copyright 2000-2007 Steven Feuerstein - Page 125

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.
Copyright 2000-2007 Steven Feuerstein - Page 126

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_nt IS 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;
Copyright 2000-2007 Steven Feuerstein - Page 127

SELECT column_value FROM TABLE ( lotsa_names ('Steven' , 100)) names; COLUMN_VALUE -----------Steven 1 ... Steven 100

tabfunc_scalar.sql

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.

tabfunc_streaming.sql

Copyright 2000-2007 Steven Feuerstein - Page 128

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

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_pkg IS 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; /
Copyright 2000-2007 Steven Feuerstein - Page 129

tabfunc_streaming.sql

Use pipelined functions to enhance performance.
CREATE FUNCTION StockPivot (p refcur_pkg.refcur_t) RETURN TickerTypeSet PIPELINED

 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.
Copyright 2000-2007 Steven Feuerstein - Page 130

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.
Copyright 2000-2007 Steven Feuerstein - Page 131

Piping rows out from a pipelined function
Add PIPELINED keyword to header 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.sql tabfunc_pipelined.sql

Pipe a row of data back to calling block or query

RETURN...nothing at all!

Copyright 2000-2007 Steven Feuerstein - Page 132

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]} )
Copyright 2000-2007 Steven Feuerstein - Page 133

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.

Copyright 2000-2007 Steven Feuerstein - Page 134

>> Object-Oriented PL/SQL

Object Types and Object-Oriented Development in PL/SQL
Copyright 2000-2007 Steven Feuerstein - Page 135

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.

Copyright 2000-2007 Steven Feuerstein - Page 136

A Very Simple Object Type Example
CREATE TYPE food_t AS OBJECT ( name VARCHAR2(100), food_group VARCHAR2 (100), grown_in VARCHAR2 (100) );

Attributes

 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.
Copyright 2000-2007 Steven Feuerstein - Page 137

Working with Simple Objects
Create a new object with a constructor. Read an attribute value
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';

Modify an attribute value

Pass an object as a parameter

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

Copyright 2000-2007 Steven Feuerstein - Page 138

"Real" object types have methods
 Constructor
– A function that returns an instance of this object type, used to initialize that instance before use.

 Static
– A subprogram applied to the object type as a whole, not any particular instance

 Member
– A subprogram applied to an instance of an object type

 Use SELF to refer to the current instance.
– Not allowed in static methods.

 You can call packaged code from within an object body.

Copyright 2000-2007 Steven Feuerstein - Page 139

An Object Type with Methods
 The timer object calculates elapsed time.  It consists of six attributes and all three types of methods.
Copyright 2000-2007 Steven Feuerstein - Page 140

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

Attributes

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

Methods

tmr.ot thisuser.*

More on Constructor Functions
 Always pass SELF as an IN OUT argument.
– SELF is assumed for member methods.
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;

 Return SELF as well.  Populate SELF inside the constructor.
Copyright 2000-2007 Steven Feuerstein - Page 141

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.
Copyright 2000-2007 Steven Feuerstein - Page 142

Let's Build a Type Hierarchy
"root", supertype of dessert subtype of food, supertype of cake subtype of dessert

food

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

dessert

cake

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

Copyright 2000-2007 Steven Feuerstein - Page 143

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

An object instantiated from food_t has three attributes. A dessert object has five attributes. A cake has seven.
Copyright 2000-2007 Steven Feuerstein - Page 144

Substitutability of Object Types
"Any object of type cake is also a dessert, is also a food."  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.
Copyright 2000-2007 Steven Feuerstein - Page 145

Populate an Object Table
 Create a table of objects of type food (root type).
CREATE TABLE sustenance OF food_t;

 Populate it with objects at different levels in hierarchy.
Use of constructor to DECLARE initialize a variable 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 Substitution of subtypes VALUES (cake_t ( 'Marzepan Delight', 'CARBOHYDRATE', 'bakery', 'N', 1634, 8, 'Happy Birthday!' ) ); food.ot END;
Copyright 2000-2007 Steven Feuerstein - Page 146

Objects in a Collection
 Create a table of objects of type food - root type.
DECLARE TYPE foodstuffs_nt IS TABLE OF food_t; Declare a nested table

fridge_contents foodstuffs_nt := foodstuffs_nt ( food_t ('Eggs benedict', 'PROTEIN', 'Farm'), dessert_t ('Strawberries and cream', 'FRUIT', 'Backyard', 'N', 2001), cake_t ( 'Chocolate Supreme', 'CARBOHYDATE', 'Kitchen', 'Y', 2001, 8, 'Happy Birthday, Veva' ) ); Insert three different BEGIN objects in the collection, ... each of a different type.
Copyright 2000-2007 Steven Feuerstein - Page 147

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
Copyright 2000-2007 Steven Feuerstein - Page 148

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);
Copyright 2000-2007 Steven Feuerstein - Page 149

treat.sql

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, For a single column main_course food_t, dessert dessert_t ) COLUMN appetizer NOT SUBSTITUTABLE AT ALL LEVELS;

At the table level

Copyright 2000-2007 Steven Feuerstein - Page 150

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

Copyright 2000-2007 Steven Feuerstein - Page 151

Constraining Substitutability to a Specific Type  Suppose I want a column of desserts to contain only cakes?
CREATE TABLE meal ( served_on DATE, Unconstrained appetizer food_t, non-substitutability main_course food_t, dessert dessert_t ) COLUMN appetizer NOT SUBSTITUTABLE AT ALL LEVELS, COLUMN dessert IS OF (ONLY cake_t) ;

Constrain to a single subtype

You can only constrain to a single type, not a list of types.
Copyright 2000-2007 Steven Feuerstein - Page 152

notsubst.sql isof.sql

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

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

food2.ot
Copyright 2000-2007 Steven Feuerstein - Page 153

Creating and Overriding Methods
 Most real-world object types will have both attributes and methods, programs that perform operations on attributes.  With inheritance, you can:
– inherit supertype methods – override or replace supertype methods with subtype implementations – add completely new methods

Copyright 2000-2007 Steven Feuerstein - Page 154

Overriding to Provide Specificity for Subtypes
 Different calculations for desserts and cakes.
CREATE OR REPLACE TYPE BODY dessert_t IS 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;

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;
Copyright 2000-2007 Steven Feuerstein - Page 155

Generic dessert prices are determined by chocolate content and age. Cake prices are driven by inscription length and size..

food2.ot

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

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

Copyright 2000-2007 Steven Feuerstein - Page 156

Requiring Overrides to Methods
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.

 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.
food2.ot
Copyright 2000-2007 Steven Feuerstein - Page 157

11g

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_gen_invoc.sql
Copyright 2000-2007 Steven Feuerstein - Page 158

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.
Copyright 2000-2007 Steven Feuerstein - Page 159

Exploring Dynamic Polymorphism
 The food and dessert types each have a price method, but cake does not.  It simply inherits the dessert method.
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. );

Copyright 2000-2007 Steven Feuerstein - Page 160

A Visual Representation
 The root price function is overridden in the dessert subtype.  The cake subtype now simply inherits its price calculation from its dessert supertype.

food

Price

the "original"

dessert

Price

An override

cake

Inherited calculation

Copyright 2000-2007 Steven Feuerstein - Page 161

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;
Copyright 2000-2007 Steven Feuerstein - Page 162

A collection of foods is populated with three different object types.

food3.ot food4.ot food5.ot dynpoly_overhead.tst

The price invocation is resolved at run-time, and not necessarily as the food_t.price method.

Other Object-Relational topics
 Object tables  The REF function and UTL_REF  Object comparisons
– MAP and ORDER

 Object views
– INSTEAD OF triggers

Copyright 2000-2007 Steven Feuerstein - Page 163

Object tables
 You can create a table of objects, known as an object table.
– Use special OF syntax to specify it.
CREATE TABLE food_table OF food_t

 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. object_table.sql
SELECT VALUE (f).name FROM food_table
Copyright 2000-2007 Steven Feuerstein - Page 164

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
Copyright 2000-2007 Steven Feuerstein - Page 165

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_t AS 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;
Copyright 2000-2007 Steven Feuerstein - Page 166

object_ref.sql

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.
Copyright 2000-2007 Steven Feuerstein - Page 167

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 ...
Copyright 2000-2007 Steven Feuerstein - Page 168

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 scalarsonly 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.
Copyright 2000-2007 Steven Feuerstein - Page 169

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

Copyright 2000-2007 Steven Feuerstein - Page 170

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...
SELF < argumentObject SELF = argumentObject SELF > argumentObject Undefined comparison

ORDER must return...
Any negative number, usually -1 0 Any positive number, usually 1 NULL

 So...you only need to write the appropriate code for your object type.
order_example.sql
Copyright 2000-2007 Steven Feuerstein - Page 171

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
Copyright 2000-2007 Steven Feuerstein - Page 172

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_insert INSTEAD OF INSERT ON images_v FOR EACH ROW BEGIN /* 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;
Copyright 2000-2007 Steven Feuerstein - Page 173

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
Copyright 2000-2007 Steven Feuerstein - Page 174

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.
Copyright 2000-2007 Steven Feuerstein - Page 175

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
Copyright 2000-2007 Steven Feuerstein - Page 176

>> 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.
Copyright 2000-2007 Steven Feuerstein - Page 177

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 = /tmp utl_file_dir = /accounts/newdev

Copyright 2000-2007 Steven Feuerstein - Page 178

Working with Database Directories
 A Directory is a database "object", define with a CREATE statement.
– You need CREATE ANY DIRECTORY privilege.
CREATE OR REPLACE DIRECTORY ERROR_LOG AS '/tmp/apps/log';

View those directories to which you have access.

SELECT owner, directory_name, directory_path FROM ALL_DIRECTORIES;

Grant READ or WRITE privileges on a directory.

GRANT READ ON DIRECTORY error_log TO SCOTT;

utlfile_92.sql
Copyright 2000-2007 Steven Feuerstein - Page 179

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

 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...
Copyright 2000-2007 Steven Feuerstein - Page 180

Reading from a File
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;

 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. exec_ddl_from_file.sql
Copyright 2000-2007 Steven Feuerstein - Page 181 getnext.sp infile.sf

Writing to a File
DECLARE fid UTL_FILE.FILE_TYPE; BEGIN fid := UTL_FILE.FOPEN ('c:\temp', 'test.txt', 'W'); UTL_FILE.PUT_LINE (fid, 'UTL_FILE'); UTL_FILE.PUT (fid, 'is so much fun'); UTL_FILE.PUTF (fid, ' that I never\nwant to %s', '&1'); UTL_FILE.FCLOSE (fid); END;

 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.
create_file.sp genaa.sql Copyright 2000-2007 Steven Feuerstein - Page 182

Closing a File
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;

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

Copyright 2000-2007 Steven Feuerstein - Page 183

Copy a File
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

 You can specify an OS directory or a database object of type DIRECTORY (as shown above)
Copyright 2000-2007 Steven Feuerstein - Page 184

Remove a File
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 remove END;

 If no error is raised, then you deleted successfully
fremove.sql fileIO92.pkg
Copyright 2000-2007 Steven Feuerstein - Page 185

Rename/move a File
 You specify target location and file name
DECLARE 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 rename END;
frename.sql fileIO92.pkg
Copyright 2000-2007 Steven Feuerstein - Page 186

Obtaining attributes of a file
CREATE OR REPLACE FUNCTION flength ( location_in IN VARCHAR2, file_in IN VARCHAR2  How big is a file? What is its ) RETURN PLS_INTEGER block size? Does the file IS exist? TYPE fgetattr_t IS RECORD ( fexists BOOLEAN,  All valuable questions. file_length PLS_INTEGER, block_size PLS_INTEGER  All answered with a call to ); UTL_FILE.FGETATTR.   fgetattr_rec fgetattr_t; BEGIN UTL_FILE.fgetattr ( location => location_in, filename => file_in, fexists => fgetattr_rec.fexists, file_length => fgetattr_rec.file_length, block_size => fgetattr_rec.block_size ); flength.sql RETURN fgetattr_rec.file_length; fileIO92.pkg END flength;

Copyright 2000-2007 Steven Feuerstein - Page 187

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. fileIO92.pkg fileIO92.tst – 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!
JFile.java xfile.pkg

Copyright 2000-2007 Steven Feuerstein - Page 188

DBMS_UTILITY.FORMAT_ERROR_BACKTR ACE
Long-standing challenge in PL/SQL: How can I find the line number on which an error was raised in PL/SQL?

 Before Oracle10g, the only way is to let the error go unhandled in your PL/SQL code!  DBMS_UTILITY.FORMAT_ERROR_STACK only gives you the full error message.
– And is recommended by Oracle in place of SQLERRM. But in Oracle10g, we have "back trace"!
Copyright 2000-2007 Steven Feuerstein - Page 189

Letting the error go unhandled…
CREATE OR REPLACE PROCEDURE proc1 BEGIN DBMS_OUTPUT.put_line ('running RAISE NO_DATA_FOUND; END; / CREATE OR REPLACE PROCEDURE proc2 l_str VARCHAR2(30) := 'calling proc1'; BEGIN DBMS_OUTPUT.put_line (l_str); proc1; END; / CREATE OR REPLACE PROCEDURE proc3 BEGIN DBMS_OUTPUT.put_line ('calling proc2; END; / IS proc1');

IS

IS proc2');

ERROR at line ORA-01403: no ORA-06512: at ORA-06512: at ORA-06512: at ORA-06512: at

1: data found "SCOTT.PROC1", line 7 "SCOTT.PROC2", line 8 "SCOTT.PROC3", line 5 line 3

Backtrace.sql
Copyright 2000-2007 Steven Feuerstein - Page 190

Displaying the “error stack” inside PL/SQL

CREATE OR REPLACE PROCEDURE proc3 IS BEGIN DBMS_OUTPUT.put_line ('calling proc2'); proc2; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.put_line ( DBMS_UTILITY.FORMAT_ERROR_STACK); END; / SQL> exec proc3 calling proc2 calling proc1 running proc1 ORA-01403: no data found

backtrace.sql

Copyright 2000-2007 Steven Feuerstein - Page 191

Displaying the contents of BACKTRACE
CREATE OR REPLACE PROCEDURE proc3 IS BEGIN DBMS_OUTPUT.put_line ('calling proc2'); proc2; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.put_line ('Error stack at top level:'); DBMS_OUTPUT.put_line (DBMS_UTILITY.FORMAT_ERROR_BACKTRACE); END; / SQL> exec proc3 calling proc2 calling proc1 running proc1 Error stack at top level: ORA-06512: at "SCOTT.PROC1", line 5 ORA-06512: at "SCOTT.PROC2", line 7 ORA-06512: at "SCOTT.PROC3", line 5
backtrace.sql bt.pkg

Copyright 2000-2007 Steven Feuerstein - Page 192

DBMS_OUTPUT: relief in sight!
 Oracle10g Release 2 offers some longawaited enhancements...
– DBMS_OUTPUT.PUT_LINE will now 32K! accept and display strings up to 32K in length. – You can set the buffer size to UNLIMITED.
SET SERVEROUTPUT ON SIZE UNLIMITED

Copyright 2000-2007 Steven Feuerstein - Page 193

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.*
Copyright 2000-2007 Steven Feuerstein - Page 194

Oracle10g

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.
CALL utl_recomp.recomp_serial ('SCOTT'); CALL utl_recomp.recomp_parallel ('SCOTT', 4); recompile.sql

Copyright 2000-2007 Steven Feuerstein - Page 195

Oracle10g

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.

Copyright 2000-2007 Steven Feuerstein - Page 196

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 UTL_MAIL.send sender ,recipients ,cc ,bcc ,subject ,message 'Hi Ya''ll, Sending email in Give it a try! Mailfully Yours, Bill' ); END;
Copyright 2000-2007 Steven Feuerstein - Page 197

/* Requires Oracle10g */ ( => => => => => => '[email protected]' '[email protected], [email protected]' '[email protected]' '[email protected]' 'Cool new API for sending email'

PL/SQL is *much* easier with UTL_MAIL in 10g.

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;

Copyright 2000-2007 Steven Feuerstein - Page 198

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!

Copyright 2000-2007 Steven Feuerstein - Page 199

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

Copyright 2000-2007 Steven Feuerstein - Page 200

Some Free PL/SQL Resources
 Oracle Technology Network PL/SQL page
http://www.oracle.com/technology/tech/pl_sql/index.html

 OTN Best Practice PL/SQL
http://www.oracle.com/technology/pub/columns/plsql/index.html

 Oracle documentation – complete, online, searchable!
http://tahiti.oracle.com/

 PL/SQL Obsession - my on-line portal for PL/SQL developers  Quest Pipelines
http://www.ToadWorld.com/SF http://quest-pipelines.com/

 I Love PL/SQL and...help improve the PL/SQL language!  PL/Vision
http://ILovePLSQLAnd.net

http://quest-pipelines.com/pipelines/dba/PLVision/plvision.htm
Copyright 2000-2007 Steven Feuerstein - Page 201

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.
Copyright 2000-2007 Steven Feuerstein - Page 202

Sponsor Documents

Or use your account on DocShare.tips

Hide

Forgot your password?

Or register your new account on DocShare.tips

Hide

Lost your password? Please enter your email address. You will receive a link to create a new password.

Back to log-in

Close