Anti-Pattern PLSQL Programming
Anti-Pattern PLSQL Programming
Anti-Pattern PLSQL Programming
Anti-Pattern
PL/SQL
Programming
Steven Feuerstein
steven@stevenfeuerstein.com
www.StevenFeuerstein.com
www.PLSQLChallenge.com
What's an Anti-Pattern?
Design Patterns in software recognizes reality:
most of the code we write follows a pattern.
Different entities, same logic.
Page 2
Page 3
PL/SQL fundamentals
Error raising and handling
Working with collections
Writing and running SQL in PL/SQL
Key maintainability techniques
Page 4
PL/SQL Obsession
http://www.ToadWorld.com/SF
Page 5
www.plsqlchannel.com
27+ hours of detailed video training
on Oracle PL/SQL
www.stevenfeuerstein.com
Monthly PL/SQL newsletter
Page 6
PL/SQL Fundamentals
Compiler optimization
Context switching in Oracle
Memory management
Page 7
Page 8
Some examples:
Unless otherwise specified, the operands of an expression
operator may be evaluated in any order.
Operands of a commutative operator may be commuted.
The actual arguments of a call or a SQL statement may be
evaluated in any order (including default actual
arguments).
10g_optimize_cfl.sql
Page 9
Page 10
Procedural
statement
executor
SQL Engine
SQL
statement
executor
Performance penalty
for many context
switches
Copyright 2013 Feuerstein and Associates
Page 11
IN VARCHAR2,
IN VARCHAR2)
Page 12
Page 13
Page 14
memory_error.sql
Page 15
Library cache
Shared SQL
Select *
from emp
Pre-parsed
Large Pool
Session 1
calc_totals
show_emps
Update emp
Set sal=...
upd_salaries
emp_rec emp%rowtype;
tot_tab tottabtype;
emp_rec emp%rowtype;
tot_tab tottabtype;
Session 1 memory
(PGA/UGA)
Session 2 memory
(PGA/UGA)
Session 2
Page 16
Page 17
show_pga_uga.sql
grantv$.sql
plsql_memory.pkg
plsql_memory_demo.sql
Page 18
bulklimit.sql
varray_collection_limit.sql
nocopy*.tst
tabfunc_pipelined.sql
Page 19
Page 20
Raising Exceptions
Oracle raises exceptions.
You can raise exceptions as well.
Use RAISE to raise an exception.
Use RAISE_APPLICATION_ERROR to pass an
application-specific message back to a user.
raise.sql
raise_application_error.sql
Page 21
Handling Exceptions
After exception is raised, the block closes and
control is passed to the exception section or
propagates unhandled to an outer block.
Exceptions raised in declaration section are not
handled.
info_for_handling.sql
excquiz*.sql
Page 22
errors_and_dml.sql
continue_past_exceptions.sql
Page 23
Page 24
Page 25
Page 26
SQLERRM Details
If you don't pass an argument to SQLERRM, it returns
the error message for the SQLCODE value.
When called outside of an exception handler, always
returns "success" message no error.
Page 27
Page 28
DBMS_UTILITY.FORMAT_CALL_STACK
The "call stack" reveals the path taken through
your application code to get to that point.
Very useful whenever tracing or logging
errors.
The string is formatted to show line number
and program unit name.
But it does not reveal the names of subprograms
in packages.
callstack.sql
callstack.pkg
Copyright 2013 Feuerstein and Associates
Page 29
DBMS_UTILITY.FORMAT_ERROR_STACK
This built-in returns the error stack in the
current session.
Possibly more than one error in stack.
Page 30
DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
The backtrace function (new to 10.2) answers the
question: "Where was my error raised?
Prior to 10.2, you could not get this information from
within PL/SQL.
Page 31
Page 32
Page 33
Apple
22
Pear
100
Orange
10023
Apricot
Page 34
Page 35
method_vs_proc.sql
plsqlloops.sp
collection_exists.sql
varray_limit.sql
delete.sql extend.sql
Page 36
Page 37
Page 38
Page 39
Page 40
Page 41
assoc_array*.sql
assoc_array_perf.tst
string_tracker2.*
Page 42
Page 43
Nested Collections
The element of a nested collection type is
itself a collection or contains a collection.
Field in record, attribute in object type
Page 44
List 2: 10001-20000
List 2: 20001-30000
string_tracker3*.*
Page 45
Page 46
Page 47
Page 48
Page 49
Page 50
authors.pkg
10g_set.sql
Page 51
in_clause.*
10g_member_of.sql
Page 52
authors.pkg
10g_submultiset.sql
Page 53
authors.pkg
10g_union.sql
Page 54
10g_intersect.sql
Page 55
10g_except.sql
Page 56
Page 57
Page 58
Page 59
Page 60
SQL in PL/SQL
SQL: the heart and soul of any Oracle-based
application.
And also the problem child.
Page 61
Page 62
Page 63
Flashback query
No more need for journal tables, history tables, etc.
select d.deptno
, (select count(*)
from emp e where
e.deptno = d.deptno)
number_staff from dept
Page 64
SELECT last_name
FROM employees
ORDER BY employee_id)
LOOP
IF employee_r.last_name LIKE '%s%'
THEN
DBMS_OUTPUT.put_line (employee_r.last_name);
END IF;
END LOOP;
END;
Page 65
Page 66
Page 67
*
l_manager
employees
employee_id = l_employee.manager_id;
Page 68
Page 69
Page 70
Page 71
Page 72
Procedural
statement
executor
SQL Engine
SQL
statement
executor
Update...
Update...
Update...
Update...
Update...
Update...
Page 73
Only one difference: BEFORE and AFTER statementlevel triggers only fire once per FORALL INSERT
statements.
Not for each INSERT statement passed to the SQL engine
from the FORALL statement.
Copyright 2013 Feuerstein and Associates
statement_trigger_and_forall.sql
Page 74
Page 75
Page 76
Iterate through
the collection
contents with a
loop.
DECLARE
TYPE employees_aat IS TABLE OF
employees%ROWTYPE;
l_employees employees_aat;
BEGIN
SELECT *
BULK COLLECT INTO l_employees
FROM employees;
bulkcoll.sql
bulkcollect.tst
process_emps (emps);
END LOOP;
CLOSE emps_in_dept_cur;
END bulk_with_limit;
bulklimit.sql
Copyright 2013 Feuerstein and Associates
Page 78
Page 79
Page 80
Page 81
forall_timing.sql
forall_examples.sql
Page 82
More on FORALL
Use any type of collection with FORALL.
Only one DML statement is allowed per
FORALL.
Each FORALL is its own "extended" DML
statement.
The collection must be indexed by integer.
The bind array must be sequentially filled.
Unless you use the INDICES OF or
VALUES OF clause.
Indexes cannot be expressions.
forall_restrictions.sql
Copyright 2013 Feuerstein and Associates
Page 83
Page 84
Page 85
Page 86
Page 87
bulkexc.sql
bulkexc_indices_of*.sql
Page 88
bulkexc.sql
bulkexc.sql
bulkexc_indices_of*.sql
Page 89
Page 90
Page 91
Relational
Table
Phase 3: FORALL from collection to table
Copyright 2013 Feuerstein and Associates
Page 92
Phase 3:
Push Data
BEGIN
OPEN employees_cur;
LOOP
fetch_next_set_of_rows (
bulk_limit_in, employee_ids, salaries, hire_dates);
EXIT WHEN employee_ids.COUNT = 0;
insert_history;
adj_comp_for_arrays (employee_ids, salaries);
update_employee;
END LOOP;
END upd_for_dept;
cfl_to_bulk_0.sql
cfl_to_bulk_5.sql
Page 93
Page 94
Page 95
Page 96
Page 97
PGA-Based Caching
When you declare variables at the package
level, their state persists in your session.
A PGA-based cache, specific to each session.
Page 98
Data retrieved
from cache
Pass Data
to Cache
Database
/ SGA
Application
Function
Not in cache;
Request data
from database
PGA
Application
Requests Data
Subsequent accesses
Database
/ SGA
Data returned
to application
Data retrieved
from cache
Data found in
cache. Database
is not needed.
Data returned
to application
Application
Function
PGA
Application
Requests Data
Copyright 2013 Feuerstein and Associates
emplu.pkg / emplu.tst
Page 99
syscache.pkg
Page 100
Page 101
11g
Page 102
11g
11g_frc_demo.sql
Page 103
11g
Page 104
11g
11g_emplu*.*
Page 105
11g
11g_frc_demo.sql
Page 106
Page 107
11g
11g_frc_session_state.sql
11g_frc_vpd.sql
11g_frc_vpd2.sql
Page 108
11g
show_frc_dependencies.sp
Page 109
11g
11g_frc_dependencies.sql
11g_frc_dependencies2.sql
Page 110
Page 111
11g_frc_encapsulation.sql
Page 112
Page 113
What's In a Name?
A name is an abstraction, a symbol that is
associated with an underlying set of data.
A common concept in history is: knowing the
"true name" of something or someone gives
one power over that thing.
Le Guin's Earthsea cycle a classic example
Let's not forget about Rumplestiltskin.
And if you know God's true namewow!
Page 114
What's in a brain?
Humans constantly seek models to describe how
the brain works.
Most have failed dismally. Where art thou, AI?
Most would agree that the brain identifies and stores
data, which can be referenced by name.
Page 115
Page 116
Names in Software
Names are crucial to human efforts to
transform our world to make it more
convenient and more comfortable.
But what do they do for software?
Page 117
Hide Information
Information hiding: a key principle of software
generally and object orientation in particular.
Human brains can handle only so much data.
We live in an age of information overload
(internet, 24 hour TV, etc.).
Page 118
Page 119
Page 120
Page 121
Page 122
Nested Subprograms
Page 123
plsql_limits.pks
string_tracker3.*
Page 124
About SUBTYPEs
You can't always use %TYPE or %ROWTYPE in your
declaration.
You can, however, always define a "subtype" or
subset of an existing type with the SUBTYPE
statement. SUBTYPE benefits:
Avoid exposing and repeating constraints.
Give application-specific names to types. Critical when
working with complex structures like collections of
records, and nested collections.
Apply constraints, such as numeric ranges, to the variable
declared with the subtype.
Page 125
Applying SUBTYPEs
Two key scenarios:
Whenever you are about to write a VARCHAR2(N)
or other constrained declaration, define a subtype
instead, preferably in a package specification.
Instead of writing a comment explaining a
declaration, put the explanation into a subtype.
Instead
of this:
Write
this:
DECLARE
l_full_name VARCHAR2(100);
l_big_string VARCHAR2(32767);
DECLARE
l_full_name employees_rp.full_name_t;
l_big_string plsql_limits.maxvarchar2;
fullname.pks
plsql_limits.pks
string_tracker3.*
Page 126
hardcoding.sql
no_more_hardcoding.sql
pkgcur.pkg
Page 127
Page 128
Page 129
Page 130
Page 131
Page 132
12c_table*.sql
12c_bind*.sql
Page 133
12c_with_function*.sql
12c_udf.sql & 12c_udf2.sql
Page 134
12c_fetch_first.sql
Copyright 2013 Feuerstein and Associates
Page 135
PACKAGE private_pkg
ACCESSIBLE BY (public_pkg)
IS
PROCEDURE do_this;
PROCEDURE do_that;
END;
12c_accessible_by.sql
Copyright 2013 Feuerstein and Associates
Page 136
Privilege-Related Features
First, let's review definer and invoker rights.
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 2013 Feuerstein and Associates
Page 137
OE Code
Sam_Sales
Order_Mgt
Place
Close Old
Orders
Cancel
OE Data
Orders
Cannot alter
table
directly.
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
Page 139
...FROM accounts
WHERE...
modify
destroy
User/Data schema
PROCEDURE mng_account IS
BEGIN
...
code.acct_mgr.destroy(...);
END;
accounts table
Page 140
invdefinv.sql
12c_grant_roles_units.sql
12c_roles_for_program_units.sql
Page 141
12c_bequeath.sql
Copyright 2013 Feuerstein and Associates
Page 142
12c_inherit_privileges.sql
Page 143
$$PLSQL_UNIT_TYPE
Returns the type of the program unit
Inside an anonymous block or non-DML trigger,
returns "ANONYMOUS BLOCK".
Copyright 2013 Feuerstein and Associates
Page 144
Page 145
Page 146
Page 147
Page 148