Escolar Documentos
Profissional Documentos
Cultura Documentos
Sponsored by AMIS
Steven Feuerstein
steven@stevenfeuerstein.com
www.StevenFeuerstein.com
Table Functions
Dynamic SQL in PL/SQL
Copyright 2011 Feuerstein and Associates
Page 2
Page 3
PL/SQL Obsession
http://www.ToadWorld.com/SF
Page 4
www.plsqlchannel.com
27+ hours of detailed video training
on Oracle PL/SQL
www.stevenfeuerstein.com
Monthly PL/SQL newsletter
www.toadworld.com/SF
Quest Software-sponsored portal
for PL/SQL developers
Page 5
memory_error.sql
Page 6
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 7
Page 8
show_pga_uga.sql
grantv$.sql
plsql_memory.pkg
plsql_memory_demo.sql
Page 9
bulklimit.sql
varray_collection_limit.sql
nocopy*.tst
tabfunc_pipelined.sql
Page 10
Conclusions
Oracle takes responsibility for managing memory
used for data (user data and "metadata"
program code, table definitions, etc.) shared by
multiple connections.
Based on parameter set by DBAs.
Page 11
Page 12
Page 13
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).
Page 14
Some Examples
T := A + B;
... T ...
...
... T ...
... A + B ...
...
... A + B ...
for i in 1 .. 10 loop
A := B + C;
...
end loop;
A := B + C;
for i in 1 .. 10 loop
...
end loop;
FOR rec in (SELECT ...)
LOOP
... do stuff
END LOOP;
SELECT ...
BULK COLLECT INTO ...
FROM ...
10g_optimize_cfl.sql
Page 15
Page 16
and then:
ALTER PROCEDURE bigproc COMPILE REUSE SETTINGS;
Page 17
11g
Page 18
11g
Page 19
11g
Page 20
Page 21
Page 22
Page 23
Page 24
plw6002.sql
Page 25
11g
Page 26
11g
One big frustration I have had with compiletime warnings is that it did not flag code like
you see above. What could be more basic?
This is finally addressed sort of in
Oracle11g with the PLW-06017 warning.
PLW-06017: an operation will raise an exception
plw6017.sql
Copyright 2011 Feuerstein and Associates
Page 27
plw5005.sql
Copyright 2011 Feuerstein and Associates
Page 28
Page 29
Page 30
Conditional Compilation
Compile selected parts of a program based on
conditions you provide with various compiler
directives.
Conditional compilation will allow you to:
Write code that will compile and run under different
versions of Oracle (relevant for future releases).
Run different code for test, debug and production
phases. That is, compile debug statements in and out of
your code.
Expose private modules for unit testing.
Page 31
Page 32
Page 33
Page 34
BEGIN
DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCE
('PROCEDURE', USER, 'POST_PROCESSED');
END;
/
PROCEDURE post_processed
IS
BEGIN
cc_postprocessed.sql
Page 35
Page 36
Using DBMS_DB_VERSION
This package, present in any Oracle Database
version supporting conditional compilation, contains
a set of Boolean constants showing absolute and
relative version information.
PROCEDURE insert_rows ( rows_in IN otn_demo_aat ) IS
BEGIN
$IF DBMS_DB_VERSION.VER_LE_10_1
$THEN
BEGIN
...
FORALL indx IN 1 .. l_dense.COUNT
INSERT INTO otn_demo VALUES l_dense (indx);
END;
$ELSE
FORALL indx IN INDICES OF rows_in
INSERT INTO otn_demo VALUES rows_in (indx);
$END
cc_bf_or_number.sql
cc_version_check.sql
Page 37
Page 38
Compile-time warnings
Try them out, see how much value you can extract
from it.
Conditional compilation
Lots of potential, mainly for use into the future
Smart tool support needed to make it feasible and
maintainable (one's code becomes very hard to
read)
Copyright 2011 Feuerstein and Associates
Page 39
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.
Page 40
Agenda - Collections
Page 41
What is a collection?
A collection is an "ordered
group of elements, all of the
same type." (PL/SQL User
Guide)
In short, a list of "stuff"
Apple
22
Pear
100
Orange
10023
Apricot
Page 42
Page 43
global_temp_tab_vs_coll.sql
Page 44
Page 45
Page 46
Glossary of Terms
Element
A collection is made up of one or more elements, all of the same
type. Also referred to as "row."
Can be of almost any valid PL/SQL type.
Index value
The "location" in the collection in which an element is found. Also
referred to as "row number."
Usually an integer, can also be a string (associative arrays only)
Dense
Every index value between lowest and highest has a defined
element.
Sparse
One or more elements between lowest and highest index values
may be undefined (gaps).
Copyright 2011 Feuerstein and Associates
Page 47
DBMS_OUTPUT
List of strings
$RDBMS_HOME\RDBMS\Admin\dbmssql.sql
Copyright 2011 Feuerstein and Associates
Page 48
Varray type
TYPE coll_name IS VARRAY (limit) OF element_type;
Page 49
Page 50
PROCEDURE my_procedure
IS
TYPE strings_t IS TABLE OF VARCHAR2(100);
Page 51
Package-level Types
PACKAGE my_types
IS
TYPE strings_t IS TABLE OF VARCHAR2(100);
Page 52
Schema-level Types
CREATE OR REPLACE TYPE strings_t IS TABLE OF VARCHAR2(100)
GRANT EXECUTE ON strings_t TO PUBLIC
Page 53
DECLARE
l_names my_types.string_t;
l_dates hire_dates_t;
l_dates HR.hire_dates_t;
l_strings DBMS_SQL.varchar2_table;
Copyright 2011 Feuerstein and Associates
Page 54
Collection Methods
The term method is used to describe
procedures and functions that defined in a class
or object type.
You invoke a method by attaching it, using dot
notation, to the name of the type/class or to an
instance of the class.
method_vs_proc.sql
Page 55
Page 56
Page 57
collection_exists.sql
plsqlloops.sp
Page 58
Page 59
Page 60
BEGIN
FOR indx IN my_collection.FIRST .. my_collection.LAST
LOOP
do_something_with (my_collection (indx));
END LOOP;
END;
plsqlloops.sp
Copyright 2011 Feuerstein and Associates
Page 61
plsqlloops.sp
Copyright 2011 Feuerstein and Associates
Page 62
varray_limit.sql
Page 63
Page 64
delete.sql
Page 65
extend.sql
Page 66
Page 67
Page 68
Associative Arrays
DECLARE
TYPE list_of_names_t IS TABLE OF employees.last_name%TYPE
INDEX BY PLS_INTEGER;
Apple
22
Pear
100
Orange
10023
Apricot
Page 69
Page 70
Page 71
DBMS_OUTPUT.put_line (
'Value at index '
|| l_index_value
|| ' = '
|| happyfamily (l_index_value)
);
l_index_value := happyfamily.NEXT (l_index_value);
END LOOP;
END;
assoc_array_example.sql
Copyright 2011 Feuerstein and Associates
Page 72
collection_of_records.sql
Copyright 2011 Feuerstein and Associates
Page 73
Page 74
aa_limits.sql
Page 75
Page 76
Page 77
Nested Tables
CREATE OR REPLACE TYPE list_of_names_t IS TABLE OF NUMBER;
nested_table_example.sql
Unordered set
of elements
Apple
Pear
Orange
Apricot
Pear
Integer index
also available
Page 78
Varrays
CREATE OR REPLACE TYPE list_of_names_t IS VARRAY (5) OF NUMBER;
varray_example.sql
Apple
Pear
Orange
Apricot
Pear
And no more
elements can fit in
this varray.
Page 79
Initialize empty
in declaration
DECLARE
TYPE numbers_t IS VARRAY (5) OF NUMBER;
salaries numbers_t := numbers_t (100, 200, 300);
BEGIN
Initialize in
declaration with
values
DECLARE
TYPE numbers_t IS TABLE OF NUMBER;
salaries numbers_t;
BEGIN
salaries := numbers_t (100, 200, 300);
Copyright 2011 Feuerstein and Associates
Initialize in
execution
section
Page 80
nt_table_of_invalid_types.sql
va_table_of_invalid_types.sql
Page 81
nested_table_example.sql
varray_example.sql
Page 82
varray_change_limit.sql
Copyright 2011 Feuerstein and Associates
Page 83
Page 84
Page 85
nested_table_change.sql
Page 86
collections_in_sql_multiset.sql
Page 87
Non-Sequential Indexing
Sometimes you simply want to add items to the
end of a list.
This makes sense if the order in which items were
added is significant.
string_tracker0.*
Page 88
Page 89
Page 90
Page 91
Page 92
array_t1
array_t2
array_t3
array_t4
array_t5
array_t6
array_t7
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;
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
Page 93
assoc_array*.sql
assoc_array_perf.tst
Page 94
add_variable_declaration;
mark_varname_as_used;
END IF;
END LOOP;
Copyright 2011 Feuerstein and Associates
string_tracker0.*
Page 95
Page 96
string_tracker1.*
Page 97
emulate_primary_key.sql
int_to_string_indexing.sql
Page 98
Page 99
List 2: 10001-20000
List 2: 20001-30000
string_tracker1.*
string_tracker2.*
string_tracker3*.*
Page 100
multdim*.*
Copyright 2011 Feuerstein and Associates
Page 101
Page 102
Page 103
BEGIN
salespkg.calc_total ('ABC');
END;
ambig_overloading.sql
Copyright 2011 Feuerstein and Associates
Page 104
all_arguments.tst
all_arguments.sql
allargs.*
Copyright 2011 Feuerstein and Associates
Page 105
Page 106
Page 107
Overloading
Overloading 1
Breakout
Overloading 2
Argument
Breakout 1
Argument 1
Argument 2
Argument 3
Argument 4
Argument 5
Breakout 1
Breakout 2
Breakout 3
Page 108
String-based index
Copyright 2011 Feuerstein and Associates
Page 109
show_all_arguments.sp
show_all_arguments.tst
cc_smartargs.pkb/load_arguments
Page 110
Is the 2nd
overloading of
TOP_SALES a
function?
Page 111
Page 112
Page 113
Page 114
Page 115
authors.pkg
10g_set.sql
Page 116
in_clause.*
10g_member_of.sql Page 117
authors.pkg
10g_submultiset.sql
Page 118
authors.pkg
10g_union.sql
Page 119
10g_intersect.sql
Page 120
10g_except.sql
Page 121
Page 122
Page 123
Page 124
Page 125
string_tracker3.*
Copyright 2011 Feuerstein and Associates
Page 126
Page 127
Page 128
UPDATE row 1
UPDATE row N
mutating.sql
A Collection-Based Solution
Since you cannot perform the processing desired in the
row-level trigger, you need to defer the action until you
get to the statement level.
If you are going to defer the work, you have to remember
what you needed to do.
An associative array is an ideal repository for this reminder list.
mutating_trigger.pkg
ranking.pkg
Copyright 2011 Feuerstein and Associates
Writes to list
Writes to list
Work List
(collection)
Process data
in the list.
Statement Trigger
Page 130
Page 131
Page 132
Page 133
Procedural
statement
executor
SQL Engine
SQL
statement
executor
Performance penalty
for many context
switches
Copyright 2011 Feuerstein and Associates
Page 134
Page 135
Procedural
statement
executor
SQL Engine
SQL
statement
executor
Update...
Update...
Update...
Update...
Update...
Update...
Page 136
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 2011 Feuerstein and Associates
statement_trigger_and_forall.sql
Page 137
Page 138
Page 139
Page 140
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
Page 142
process_emps (emps);
END LOOP;
CLOSE emps_in_dept_cur;
END bulk_with_limit;
bulklimit.sql
Copyright 2011 Feuerstein and Associates
Page 143
Page 144
Page 145
Page 146
Page 147
FORALL Agenda
Introduction to FORALL
Using the SQL%BULK_ROWCOUNT
Referencing fields of collections of records
Using FORALL with sparsely-filled collections
Handling errors raised during execution of
FORALL
Page 148
forall_timing.sql
forall_examples.sql
Page 149
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 2011 Feuerstein and Associates
Page 150
Page 151
11g
Page 152
Page 153
Page 154
Page 155
Page 156
Page 157
Page 158
Page 159
Relational
Table
Phase 3: FORALL from collection to table
Copyright 2011 Feuerstein and Associates
Page 160
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 161
Page 162
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:
"just" rows and columns!
After all, not everything can be done in SQL.
Page 163
Page 164
Page 165
Page 166
COLUMN_VALUE
-----------Steven 1
...
Steven 100
tabfunc_scalar.sql
Page 167
tabfunc_streaming.sql
Page 168
BEGIN
INSERT INTO tickertable
SELECT *
FROM TABLE (stockpivot (CURSOR (SELECT *
FROM stocktable)));
END;
/
tabfunc_streaming.sql
Page 169
Page 170
Page 171
RETURN...nothing at
all!
Page 172
Page 173
Page 174
Page 175
'DROP ' ||
l_type || ' ' || l_name
'BEGIN ' ||
l_proc_name || ' (' ||
l_parameters || '); END;'
Page 176
Page 177
Page 178
Page 179
dropwhatever.sp
create_index.sp
settrig.sp
ddl_insuff_privs.sql
Page 180
Page 181
Page 182
Page 183
sys_refcursor;
empnos
numlist_t;
enames
namelist_t;
l_employees employee_t;
BEGIN
OPEN emp_cv FOR 'SELECT empno, ename FROM emp_' || loc_in;
FETCH emp_cv BULK COLLECT INTO empnos, enames;
CLOSE emp_cv;
EXECUTE IMMEDIATE 'SELECT * FROM emp_' || loc_in
BULK COLLECT INTO l_employees;
END;
Copyright 2011 Feuerstein and Associates
return_nested_table.sf
Page 184
Quiz!
What's wrong with
this code?
How would you fix
it?
PROCEDURE process_lineitem (
line_in IN PLS_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;
Page 185
PROCEDURE process_lineitem (
line_in IN INTEGER)
IS
BEGIN
EXECUTE IMMEDIATE
'BEGIN process_line'||
line_in ||'; END;';
END;
IF line_in = 2
THEN
process_line2;
END IF;
...
IF line_in = 22045
THEN
process_line22045;
END IF;
END;
Page 186
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.
Page 187
Page 188
Page 189
BEGIN
FOR each-column-in-table LOOP
add-column-to-select-list;
END LOOP;
Parse the
variable SQL
Define each
column
Execute the
query
Extract each
value
LOOP
fetch-a-row;
FOR each-column-in-table LOOP
DBMS_SQL.COLUMN_VALUE (cur, nth_col, val);
END LOOP;
END LOOP;
END;
Also:
dyn_placeholder.*
Copyright 2011 Feuerstein and Associates
Page 191
Page 192
desccols.pkg
desccols.tst
Copyright
Steven
Feuerstein - Page 193
Copyright
2011 2000-2008
Feuerstein and
Associates
Page 193
Page 194
tabcount.sf
tabcount81.sf
Copyright 2011 Feuerstein and Associates
Page 196
Page 197
Page 198
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 199
Page 200
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 2011 Feuerstein and Associates
Page 201
DBMS_UTILITY.FORMAT_ERROR_STACK
This built-in returns the error stack in the
current session.
Possibly more than one error in stack.
Page 202
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 203
Page 204
errors_and_dml.sql
Page 205
Page 206
Page 207
dbms_errlog.sql
Page 208
UPDATE employees
SET salary = salary_in
LOG ERRORS REJECT LIMIT 100;
Page 209
Page 210
dbms_errlog_helper.sql
dbms_errlog_helper_demo.sql
Copyright 2011 Feuerstein and Associates
Page 211
Page 212
Page 213
11g
Page 214
Page 214
11g
Page 215
Page 215
11g
Page 216
Page 216
11g
Page 217
11g
Page 218
11g
Page 219
Page 219
11g
The SIMPLE_INTEGER
and real Native Compilation
Native Compilation
Page 220
11g
11g
Page 222
11g
11g_native_sequence.sql
Page 223
11g
11g_continue.sql
local_modules_with_continue.sql
Page 224
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 is 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 2011 Feuerstein and Associates
Page 225
Page 226
USAGE
The way the identifier is used (DECLARATION,
ASSIGNMENT, etc.)
SIGNATURE
Unique value for an identifier. Especially helpful when
distinguishing between overloadings of a subprogram or
"connecting" subprogram declarations in package with
definition in package body.
Page 227
11g
plscope_demo_setup.sql
plscope_all_idents.sql
plscope_var_declares.sql
plscope_gvar_declares.sql
plscope_var_changes.sql
Page 228
11g
plscope_unused_exceptions.sql
plscope_hierarchy.sql
plscope_naming_conventions.sql
Page 229
11g
plscope_helper_setup.sql
plscope_helper.pkg
Page 230
11g
PL/Scope Summary
PL/Scope gives you a level of visibility into
your code that was never before possible.
The ALL_IDENTIFIERS view is not
straightforward.
Use the helper package to get you started.
Hopefully we will see PL/Scope interfaces built
into the most popular IDEs.
Page 231
11g
Interoperability
Convert DBMS_SQL cursor to cursor variable
Convert cursor variable to DBMS_SQL cursor
Improved security
Random generation of DBMS_SQL cursor handles
Denial of access/use of DBMS_SQL with invalid cursor
or change of effective user.
Page 232
11g
exec_ddl_from_file.sql
exec_ddl_from_file_11g.sql
Page 233
Interoperability
DBMS_SQL.TO_REFCURSOR
Cursor handle to cursor variable
Useful when you need DBMS_SQL to bind and
execute, but easier to fetch through cursor
variable.
DBMS_SQL.TO_CURSOR_NUMBER
Cursor variable to cursor handle
Binding is static but SELECT list is dynamic
Page 234
11g
DBMS_SQL.TO_REFCURSOR
Converts a SQL cursor number to a weak cursor
variable, which you can use in native dynamic SQL
statements.
Before passing a SQL cursor number to the
DBMS_SQL.TO_REFCURSOR function, you must OPEN,
PARSE, and EXECUTE it (otherwise an error occurs).
After you convert a SQL cursor number to a REF
CURSOR variable, DBMS_SQL operations can access it
only as the REF CURSOR variable, not as the SQL cursor
number.
Using the DBMS_SQL.IS_OPEN function to see if a
converted SQL cursor number is still open causes an error.
Copyright 2011 Feuerstein and Associates
11g_to_refcursor.sql
Page 235
11g
DBMS_SQL.TO_CURSOR_NUMBER
Converts a REF CURSOR variable (either strong
or weak) to a SQL cursor number, which you
can pass to DBMS_SQL subprograms.
Before passing a REF CURSOR variable to the
DBMS_SQL.TO_CURSOR_NUMBER function,
you must OPEN it.
After you convert a REF CURSOR variable to a
SQL cursor number, native dynamic SQL
operations cannot access it.
Copyright 2011 Feuerstein and Associates
11g_to_cursorid.sql
Page 236
11g
Improved Security
Cursor handles generated by the
DBMS_SQL.OPEN_CURSOR function are now
random and not sequential.
Pass an invalid cursor handle to many
DBMS_SQL programs and DBMS_SQL is then
disabled.
Have to reconnect.
11g_random_cursor_handle.sql
11g_access_denied_1.sql
11g_effective_user_id.sql
Page 237
11g
Page 238
11g
11g_gen_invoc.sql
Copyright 2011 Feuerstein and Associates
Page 239
analyzedep*.*
code_referencing_tables.sql
layer_validator*.*
Page 240
Impact of change:
You can minimize invalidation of program units.
Page 241
What is hard-coding?
Why is it a problem?
The opposite of hard-coding
Where's the hard-coding?
Specific techniques for getting rid of the many
forms of hard-coding
Page 242
Page 243
Page 244
Too bad!
Whenever anything changes, you have to find all
the places you explicitly coded it, and fix them.
Copyright 2011 Feuerstein and Associates
Page 245
Easy Coding
It's hard fixing hard-codings in multiple places. It'd
be easier to fix things in one place. It really does
make things easier.
Page 246
Hard-Coding Avoidance:
Principles and Concepts
Single point of definition (no repetition)
You should always aim for a single point of definition or
SPOD for everything in your application.
Page 247
hardcoding.sql
Page 248
Constrained declarations
Especially VARCHAR2(n)
Page 249
Page 250
Page 251
Page 252
Page 253
Page 254
Page 255
WHEN OTHERS
THEN
IF SQLCODE = -24381
THEN
...
ELSIF SQLCODE = -1855
THEN
...
ELSE
RAISE;
END;
e_forall_failure EXCEPTION;
PRAGMA EXCEPTION_INIT (
e_forall_failure, -24381);
BEGIN
....
EXCEPTION
WHEN e_forall_failure
THEN
...
END;
Page 256
Conclusions
Magic value hard-coding is the most
commonly recognized form of hard-coding.
It is also the easiest to remove from your
code.
Use constants or functions to hide the value,
define that value in one place.
"Single point of definition" or SPOD
Page 257
Page 258
Page 259
fetch_into_record.sql
Copyright 2011 Feuerstein and Associates
Page 260
Page 261
Page 262
no_more_hardcoding.sql
Copyright 2011 Feuerstein and Associates
Page 263
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.
Copyright 2011 Feuerstein and Associates
Page 264
subtype_examples.sql
Page 265
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 266
Conclusions
Declarations offer a danger of hard-coding of
both datatype and constraint on that type.
Assume that over time everything will change.
Apply the same "single point of definition"
principle to your declarations.
Use %TYPE and %ROWTYPE whenever possible.
Fall back on subtypes to define application specific
types and PL/SQL limits.
Page 267
Page 268
PagePage
269269
The Backend
Order
Table
Item
Table
Customer
We don't set rules on
Table
how, when and where
SQL should be written in
The result? Slow, buggy
PL/SQL.
code that is difficult to
Page 270
Page 271
Page 272
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 273
PagePage
274274
Page 275
SQL as a Service
Think of SQL as a service that is provided to you, not
something you write.
Or if you write it, you put it somewhere so that it can be
easily found, reused, and maintained.
Application
Code
Intermediate Layer
Order
Table
Item
Table
Page 276
11g_frc_demo.sql
11g_emplu.*
Page 277
Page 278
Page 279
Conclusions
SQL statements are among the most critical
parts of your application.
You should have a clearly defined set of
guidelines about when, where and how to
write SQL.
Most important: Don't repeat SQL statements
(a form of hard-coding).
Page 280
Page 281
Page 282
Logging Errors
We usually, but not always, want to write error
information out to a log table. How's this?
WHEN NO_DATA_FOUND
THEN
l_code := SQLCODE;
INSERT INTO errlog
VALUES ( l_code
, 'No company for id ' || TO_CHAR ( v_id )
, 'fixdebt', SYSDATE, USER );
WHEN OTHERS
THEN
l_code := SQLCODE; l_errm := SQLERRM;
INSERT INTO errlog
VALUES (l_code, l_errm, 'fixdebt', SYSDATE, USER );
RAISE;
END;
Page 283
Page 284
Page 285
Page 286
Examples...
DBMS_OUTPUT.PUT_LINE (previously discussed)
UTL_FILE.GET_LINE
exec_ddl_from_file_bad.sql
Jfile.java, xfile.pkg
Copyright 2011 Feuerstein and Associates
Page 287
Page 288
PROCEDURE my_monster_application
IS
BEGIN
Insert_a_bunch_of_rows;
Change_lots_more_data;
-- COMMIT;
END;
Page 289
While committing,
also pass trace
information.
Copyright 2011 Feuerstein and Associates
my_commit.*
Page 290
Page 291
Page 292
Get a promotion
I can improve my application code much more quickly than
those who hard-code SQL.....
The Result Cache is a great example of this.
Copyright 2011 Feuerstein and Associates
293
Page 293
Page 294
Your Reward
Elegant, functional code that you and others
can maintain easily
The respect of your peers
A deep sense of satisfaction with a job well
done
The opportunity to continue making a very
fine living, mostly from just thinking about
abstractions.
Page 295
Extreme Modularization
Spaghetti code is the bane of
a programmer's existence.
It is impossible to understand
and therefore debug or
maintain code that has long,
twisted executable sections.
Fortunately, it is really easy to
make spaghetti code a thing
of the past.
Copyright 2011 Feuerstein and Associates
Organize your
code so that the
executable
section has no
more than fifty
lines of code.
Page 296
Page 297
While there are still unhandled calls in the queue, assign them to
employees who are under-utilized (have fewer calls assigned to
them then the average for their department).
Page 298
Page 299
Explanation of Subprograms
Function calls_are_unhandled: takes no arguments,
returns TRUE if there is still at least one unhandled
call, FALSE otherwise.
Function current_caseload: returns the number of
calls (case load) assigned to that employee.
Function avg_caseload_for_dept: returns the average
number of calls assigned to employees in that
department.
Procedure assign_next_open_call: assigns the
employee to the call, making it handled, as opposed
to unhandled.
Copyright 2011 Feuerstein and Associates
Page 300
locmod_step_by_step.sql
Page 301
Page 302
Page 303
distribute
_calls
show_
caseload
PROCEDURE distribute_calls (
department_id_in IN departments.department_id%TYPE
)
IS BEGIN ... END distribute_calls;
END;
locmod_step_by_step.sql
current_
caseload
Page 304
Page 305
locmod_step_by_step.sql
topdown*.*
Page 306
Page 307
Page 308
Page 309
Page 310
www.plsqlchannel.com
27+ hours of detailed video training
on Oracle PL/SQL
www.stevenfeuerstein.com
Monthly PL/SQL newsletter
www.toadworld.com/SF
Quest Software-sponsored portal
for PL/SQL developers
Page 311