28
--------------------------------------------- By Yu, Fang ([email protected]) PL/SQL Programming Tips Contents Naming Conventions ..................................................................................................................................... 3 Why need naming convention .................................................................................................................. 3 Some facts that matter ............................................................................................................................. 3 General Guidelines.................................................................................................................................... 3 Naming Conventions ................................................................................................................................. 4 Coding Style .................................................................................................................................................. 5 General Coding Style ................................................................................................................................. 5 Some Examples of SQL Statement Formatting ......................................................................................... 5 Tools that can format SQL Statement....................................................................................................... 6 Code Commenting .................................................................................................................................... 7 Best Practices ................................................................................................................................................ 8 Literals, constants and variables ............................................................................................................... 8 Data Types................................................................................................................................................. 9 Flow Control ............................................................................................................................................ 11 Exception Handling ................................................................................................................................. 13 Dynamic SQL ........................................................................................................................................... 14 Packages, Functions and Procedures ...................................................................................................... 14 CASE/IF/DECODE/NVL/NVL2/COALESCE ................................................................................................ 14 Some Built-in Utilities ................................................................................................................................. 15 PLSQL_OPTIMIZE_LEVEL ......................................................................................................................... 15 PLSQL_WARNINGS .................................................................................................................................. 16 PLSQL_DEBUG ......................................................................................................................................... 16 Native Compilation ................................................................................................................................. 16 Conditional Compilation ......................................................................................................................... 17 DML Error Logging .................................................................................................................................. 18 Use contexts to store global data ........................................................................................................... 19 DBMS_APPLICATION_INFO ..................................................................................................................... 19 DBMS_SESSION ....................................................................................................................................... 21

PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang ([email protected]) Naming Conventions The following tables will illustrate

Embed Size (px)

Citation preview

Page 1: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

PL/SQL Programming Tips

Contents Naming Conventions ..................................................................................................................................... 3

Why need naming convention .................................................................................................................. 3

Some facts that matter ............................................................................................................................. 3

General Guidelines .................................................................................................................................... 3

Naming Conventions ................................................................................................................................. 4

Coding Style .................................................................................................................................................. 5

General Coding Style ................................................................................................................................. 5

Some Examples of SQL Statement Formatting ......................................................................................... 5

Tools that can format SQL Statement ....................................................................................................... 6

Code Commenting .................................................................................................................................... 7

Best Practices ................................................................................................................................................ 8

Literals, constants and variables ............................................................................................................... 8

Data Types ................................................................................................................................................. 9

Flow Control ............................................................................................................................................ 11

Exception Handling ................................................................................................................................. 13

Dynamic SQL ........................................................................................................................................... 14

Packages, Functions and Procedures ...................................................................................................... 14

CASE/IF/DECODE/NVL/NVL2/COALESCE ................................................................................................ 14

Some Built-in Utilities ................................................................................................................................. 15

PLSQL_OPTIMIZE_LEVEL ......................................................................................................................... 15

PLSQL_WARNINGS .................................................................................................................................. 16

PLSQL_DEBUG ......................................................................................................................................... 16

Native Compilation ................................................................................................................................. 16

Conditional Compilation ......................................................................................................................... 17

DML Error Logging .................................................................................................................................. 18

Use contexts to store global data ........................................................................................................... 19

DBMS_APPLICATION_INFO ..................................................................................................................... 19

DBMS_SESSION ....................................................................................................................................... 21

Page 2: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

DBMS_PROFILER ..................................................................................................................................... 21

DBMS_TRACE .......................................................................................................................................... 21

Some Traps.................................................................................................................................................. 22

Pipelined table function and cardinality ................................................................................................. 22

DBMS_RANDOM ..................................................................................................................................... 26

The literal string length limit in SQL statement ...................................................................................... 27

Page 3: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

Naming Conventions

Why need naming convention

Good and consistent naming manner, obviously, will make the PL/SQL code easier to read and maintain.

The result is that the code is most likely to be more robust and with higher quality. What’s more, it will

win higher reputation for the programmer.

Some facts that matter

Since PL/SQL language is closely associated with Oracle, the variable names used in the PL/SQL code are

limited to the restriction of Oracle.

- The length of the names cannot be longer than 30 characters.

- The name is case insensitive.

General Guidelines

There are some general guidelines for the naming manner for the PL/SQL code.

- Use meaningful and specific names, abbreviations and table/column alias.

- Do not use reserved words as variable names. Use the following SQL statement to see which

words are reserved by Oracle.

SELECT keyword FROM v$reserved_words;

- Avoid redundant or meaningless prefixes and suffixes. Remember there is 30 characters length

restriction. For example, there is no need to add “_table” as the suffix of the table name.

- Do not quote name with double quotes (“”). Following example illustrates that if the table name

is double quoted, it will causes some troubles when querying the table.

SQL> create table "HelloWorld" (id number);

Table created.

SQL> select * from helloworld; select * from helloworld

*

ERROR at line 1: ORA-00942: table or view does not exist

SQL> select * from HelloWorld;

select * from HelloWorld

* ERROR at line 1:

ORA-00942: table or view does not exist

SQL> select * from "HelloWorld"; no rows selected

Page 4: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

Naming Conventions

The following tables will illustrate the naming conventions for pl/sql variables, cursors, collections and

oracle objects.

- Naming Conventions for Variables

Type of Element Naming Convention Example

Variable declared in a PL/SQL block l_<xxx> l_emp_no

Constant declared in a PL/SQL block c_<xxx> c_max_str_length

Variable declared at the package level g_<xxx> g_analysis_plan

Constant declared at the package level gc_<xxx> gc_max_str_length

IN parameter p_<xxx>_in or p_<xxx>_i p_emp_no_in

OUT parameter p_<xxx>_out or p_<xxx>_o p_emp_no_out

IN OUT parameter p_<xxx>_inout or p_<xxx>_io p_emp_no_inout

Exception variable e_<xxx> e_name_not_found

- Naming Conventions for Cursors

Type of Element Naming Convention Example

Explicit cursor

[l|g]_<xxx>_cur

l_employees_cur g_employees_cur

Cursor variables [l|g]_<xxx>_cv l_employees_cv g_employees_cv

- Naming Conventions for Records and Collections

Type of Element Naming Convention Example

Record types [l|g]_<xxx>_rt l_emp_info_rt

Record variables The same as general variable, in singular form l_employee_info

Associate Array type [l|g]_<xxx>_aat l_employees_aat

Nested Table type [l|g]_<xxx>_ntt l_employees_ntt

Varray type [l|g]_<xxx>_vat l_employees_vat

Collection varaibles The same as general variable, in plural form l_employees

- Naming Conventions for Database Objects

Type of Element Naming Convention Example

Types – Objects t_<xxx>[_o] t_user_objects

Types – Nested Table t_<xxx>_t[able] t_user_objects_table

Packages pack_<xxx> pack_fermat

Triggers tri_<xxx> tri_lo_entity

Sequences seq_<xxx> seq_lo_entity

Views v_<xxx> or mv_<xxx> v_lo_entity

Indexes i[n]_<xxx> or ui[n]_<xxx> i1_lo_entity

Synonyms s_<xxx> s_entity

Global temporary table gtt_<xxx> or <xxx>_gtt user_gtt

Page 5: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

Coding Style

General Coding Style

- Keywords are written in uppercase while variable names are written in lowercase.

- Use 3 white spaces as the code line indention, don’t use tab keystroke, as different platforms

treat the tab keystroke differently.

- Specify table columns explicitly in SELECT and INSERT statements.

- Keep SQL statement keywords right-aligned or left-aligned.

The table below shows the general PL/SQL coding style.

PROCEDURE set_salary(p_empno_in IN emp.empno%TYPE)

IS

CURSOR l_emp_cur(p_empno emp.empno%TYPE) IS

SELECT ename , sal

FROM emp WHERE empno = p_empno

ORDER BY ename;

l_emp l_emp_cur%ROWTYPE; l_new_sal emp.sal%TYPE;

BEGIN OPEN l_emp_cur(p_empno_in);

FETCH l_emp_cur INTO l_emp;

CLOSE l_emp_cur; -- get_new_salary (p_empno_in => in_empno , p_sal_out => l_new_sal);

-- Check whether salary has changed IF l_emp.sal <> l_new_sal THEN UPDATE emp

SET sal = l_new_sal WHERE empno = p_empno_in;

END IF; END set_salary;

Some Examples of SQL Statement Formatting

- Write the whole SQL statement in one line

SELECT e.job, e.deptno FROM emp e WHERE e.name = 'SCOTT' AND e.sal > 100000

- Keep the SQL statement keywords right-aligned

SELECT e.JOB,

e.deptno

FROM emp e WHERE e.name = 'SCOTT'

AND e.sal > 100000

Page 6: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

- Keep the SQL statement keywords left-aligned

SELECT e.JOB, e.deptno

FROM emp e

WHERE e.name = 'SCOTT' AND e.sal > 100000

Tools that can format SQL Statement

- Instant SQL Formatter (http://www.dpriver.com/pp/sqlformat.htm)

- Oracle SQL Developer

- Toad for Oracle (Format tools)

Page 7: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

Code Commenting

Obviously, the comment for the code is very important. It can not only make the code easier to

understand, but also can be used by some tools to generate code documentation.

- PLDOC

Pldoc is an open-source utility for generating HTML documentation of code written in Oracle

PL/SQL. Please refer to pldoc official site (http://pldoc.sourceforge.net/maven-site) for details.

Below is a code example which follows the pldoc convention.

PACKAGE pack_syspar IS /** * Project: Test Project (<a href="http://pldoc.sourceforge.net">PLDoc</a>)<br/> * Description: System Parameters Management<br/> * DB impact: YES<br/> * Commit inside: NO<br/> * Rollback inside: NO<br/> * @headcom */

/** Gets system parameter value. * @param p_name parameter name * @return parameter value * @throws no_data_found if no parameter with such name found */ FUNCTION get_char (p_name_in VARCHAR2) RETURN VARCHAR2; END pack_syspar ;

/

- For those standalone (i.e. at schema level) PL/SQL code units, the comments for the units should

not put in front of the code unit, otherwise the comments will not kept in the data dictionary.

Below is an example of trigger comments.

Instead of putting the comments in front of the trigger TRI_MYTAB_BI…

/******************************************************************* Copyright YYYY by <Company Name> All Rights Reserved. <Short synopsis of trigger's purpose. Required.> <Optional design notes.> *******************************************************************/

CREATE OR REPLACE TRIGGER tri_mytab_bi

BEFORE INSERT ON mytab FOR EACH ROW

DECLARE -- local variables here BEGIN NULL;

END tri_mytab_bi;

Page 8: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

The comments should be put “inside” the trigger definition, please note the comma behind the

trigger comments.

CREATE OR REPLACE TRIGGER tri_mytab_bi BEFORE INSERT ON mytab

FOR EACH ROW

DECLARE -- local variables here BEGIN NULL;

END tri_mytab_bi

/******************************************************************* Copyright YYYY by <Company Name> All Rights Reserved. <Short synopsis of trigger's purpose. Required.> <Optional design notes.> *******************************************************************/ ;

Best Practices

Literals, constants and variables

- Avoid using literals directly in the code, abstract literals behind package constants.

For example, instead of using the literal ‘LEADER’ in the code directly like blow…

-- Bad DECLARE

l_function player.function_name%TYPE;

BEGIN SELECT p.function

INTO l_function FROM player p

WHERE …

-- IF l_function = ‘LEADER’

THEN …

Try to extract the literal ‘LEADER’ inside one package, like PACK_CONSTANTS. And then

reference this constant in the code unit…

-- Good CREATE OR REPLACE PACKAGE pack_constants

IS gc_leader CONSTANT player.function_name%TYPE := ‘LEADER’;

END pack_constants ; /

DECLARE

Page 9: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

l_function player.function_name%TYPE;

BEGIN SELECT p.function INTO l_function FROM player p WHERE …

-- IF l_function = pack_constants.gc_leader THEN

- Use a function to return a constant if the “constant” value may change at times. This way, the

code units that depend on this function will not become invalid and need recompile if the value

returned by the function is changed.

- Do not use public global variables, use getter/setter or parameters-passing.

- Never put all of a system’s constants in a single package. Try to put the constants in separate

packages according to the constants usage.

- Avoid initializing variables using functions in the declaration section. Instead, assign the

variables using functions in the body section. This way, if the function raises the exception, such

exception can be caught.

For example, don’t write the code like this…

-- Bad DECLARE

l_code_section VARCHAR2(30) := ‘TEST_PCK’; l_company_name VARCHAR2(30) := util_pck.get_company_name(in_id => 47);

BEGIN …

END;

Write it like this…

-- Good DECLARE

l_code_section VARCHAR2(30) := ‘TEST_PCK’; l_company_name VARCHAR2(30);

BEGIN

<<init>> BEGIN

l_companyName := util_pck.get_company_name(inId => 47); EXCEPTION

WHEN VALUE_ERROR THEN …;

END; END;

Data Types

- Anchor parameters and variables using %TYPE (or %ROWTYPE for cursor or entire table). When

the table structure or cursor definition changes, the variables don’t need to update.

- Use SUBTYPE to avoid hard-coded variable length declarations. See below for an example. Since

Oracle restricts the length of the object name to be no longer than 30, so defining the string

Page 10: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

(varchar2) variables with the length of 30 is a common practice. Instead of hard coding 30 in the

variable length declarations, try to define a subtype in a separate package.

Instead of declaring the variable l_code_section with the length of 30…

-- Bad l_code_section VARCHAR2(30) := ‘TEST_PCK’;

… Try to create a package PACK_TYPES to define the subtypes and use these subtypes to define

the variables.

-- Good CREATE OR REPLACE PACKAGE PACK_TYPES

AS SUBTYPE t_oracle_name IS VARCHAR2(30);

SUBTYPE t_oracle_max_varchar IS VARCHAR2(4000); subtype t_plsql_max_varchar IS VARCHAR2(32767);

END PACK_TYPES;

/

l_code_section PACK_TYPES.t_oracle_name := ‘TEST_PCK’;

- Avoid using CHAR data type, stick to VARCHAR2 data type. Use VARCHAR2(1) to replace CHAR.

- Never use zero-length strings to substitute NULL.

-- Bad l_char := ‘’;

-- Good l_char := NULL;

- Use CLOB, NCLOB, BLOB or BFILE for unstructured content in binary or character format. Do not

use LONG or LONG RAW. LOB data types provide efficient, random, piece-wise access to the

data. Some differences between LOB data types and LONG (LONG RAW) are listed below…

o A table can contain multiple LOB columns but only one LONG column.

o A table containing one or more LOB columns can be partitioned, but a table containing a

LONG column cannot be partitioned.

o The maximum size of a LOB is 8 terabytes, and the maximum size of a LONG is only 2

gigabytes.

o LOBs support random access to data, but LONGs support only sequential access.

o LOB data types (except NCLOB) can be attributes of a user-defined object type but LONG

data types cannot.

- NUMBER vs. PLS_INTEGER vs. SIMPLE_INTEGER (New in 11g, always not null).

When declaring an integer variable, PLS_INTEGER is the most efficient numeric data type

because its value requires less storage than INTEGER or NUMBER values, which are represented

internally as 22-byte Oracle numbers. Also, PLS_INTEGER operations use machine arithmetic, so

they are faster than NUMBER or INTEGER (integer is subtype of NUMBER) operations, which use

Page 11: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

library arithmetic. SIMPLE_INTEGER is introduced in 11g, if the integer will always not null use

this data type. SIMPLE_INTEGER is a subtype of the PLS_INTEGER data type and can dramatically

increase the speed of integer arithmetic in natively compiled code, but only shows marginal

performance improvements in interpreted code.

- Avoid using ROWID or UROWID (Universal ROWID). It is a dangerous practice to store ROWIDs in

a table, except for some very limited scenarios of runtime duration. Any manually explicit or

system generated implicit table reorganization will reassign the row’s ROWID and break the data

consistency.

- Minimize data type conversion as it takes time.

DECLARE n NUMBER := 0;

c CHAR(2); BEGIN

n := n + 15; -- converted implicitly; slow

n := n + 15.0; -- not converted; fast c := 25; -- converted implicitly; slow

c := TO_CHAR(25); -- converted explicitly; still slow c := '25'; -- not converted; fast END;

/

- Bigger is better for VARCHAR2 variables. VARCHAR2 variables below than 4001 bytes (2000

bytes in 9i) have their memory allocated in full at declaration time. VARCHAR2 variables larger

than 4000 bytes (1999 bytes in 9i) have their memory allocated at assignment time, based on

the data assigned to them. As a result, defining large variables that contain little data wastes

memory, unless you move above the optimization threshold at which point no memory is

wasted. If in doubt, define VARCHAR2 (32767) variables.

Flow Control

- Always label the loops. The example below labels the FOR loop with the name of

“process_employees”.

BEGIN

<<process_employees>> FOR r_employee IN (SELECT * FROM emp)

LOOP …

END LOOP process_employees;

END;

- Always use a FOR loop to process the complete cursor results unless use the bulk operation

- Always use a WHILE loop to process a loose array. The collection “t_employees” in the example

below is a loose array, so use the WHILE loop.

DECLARE l_index PLS_INTEGER;

Page 12: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

BEGIN

l_index := t_employees.FIRST();

<<ProcessEmployees>>

WHILE l_index IS NOT NULL LOOP

… l_index := t_employees.NEXT(l_index);

END LOOP process_employees; END;

- Always use FIRST..LAST when iterating through collections with a loop

BEGIN

<<process_employees>> FOR idx IN t_employees.FIRST()..t_employees.LAST()

LOOP …

END LOOP process_employees;

END;

- Always use EXIT WHEN instead of an IF statement to exit from a loop

-- Bad BEGIN <<process_employees>>

LOOP ...

IF ...

THEN

EXIT process_employees;

END IF; ...

END LOOP process_employees; END;

-- Good BEGIN <<process_employees>>

LOOP ...

EXIT process_employees WHEN (...);

END LOOP process_employees; END;

- Never EXIT from within any FOR loop, use LOOP or WHILE loop instead

- Avoid hard-coded upper or lower bound values with FOR loops

- Never issue a RETURN statement inside a loop

Page 13: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

Exception Handling

- Never handle unnamed exceptions using the error number, instead using “EXCEPTION_INIT” to

name the exception. The example below illustrates this idea.

-- Bad -- ORA-00001: unique constraint violated

BEGIN ...

EXCEPTION

WHEN OTHERS THEN IF SQLCODE = -1

THEN ...

END IF;

END;

-- Good DECLARE e_employee_exists EXCEPTION;

PRAGMA EXCEPTION_INIT(-1, e_employee_exists);

... BEGIN

... EXCEPTION

WHEN e_employee_exists THEN

... END;

- Never assign predefined exception names to user defined exceptions

- Avoid use of WHEN OTHERS clause in an exception section without any other specific handlers.

-- Good EXCEPTION

WHEN DUP_VAL_ON_INDEX THEN

update_instead (...); WHEN OTHERS

THEN err.log;

RAISE;

- Avoid use of EXCEPTION_INIT pragma for -20, NNN error (-20,999 ~ -20,000)

- Use DBMS_UTILITY.format_error_stack instead of SQLERRM to obtain the full error message

Page 14: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

Dynamic SQL

- Always use a string variable to execute dynamic SQL, don’t use the string literal behind the

“EXECUTE IMMEDIATE” directly. The reason is that using string variable is easier for debug. See

the example below for the illustration.

-- Bad DECLARE

l_empno emp.empno%TYPE := 4711; BEGIN

EXECUTE IMMEDIATE ‘DELETE FROM emp WHERE epno = :p_empno’ USING l_empno; END;

-- Good DECLARE l_empno emp.empno%TYPE := 4711;

l_sql VARCHAR2(32767); BEGIN

l_sql := ‘DELETE FROM emp WHERE epno = :p_empno’;

EXECUTE IMMEDIATE l_sql USING l_empno; EXCEPTION

WHEN others THEN

DBMS_OUTPUT.PUT_LINE(l_sql);

END;

- Use bind variables. Do not concatenate strings unless needed to identify schema or table/view.

- Format dynamic SQL strings as nicely as in static SQL.

Packages, Functions and Procedures

- Try to keep packages small. Include only few procedures and functions that are used in the same

context.

- Always use forward declaration for private functions and procedures in packages.

- Avoid standalone procedures or functions – put them in packages.

- Avoid using RETURN statements in a procedure (one way in one way out).

- Try to use no more than one RETURN statement within a function.

- Never use OUT parameters to return values from a function.

CASE/IF/DECODE/NVL/NVL2/COALESCE

- Try to use CASE rather than an IF statement with multiple ELSIF paths.

-- Bad IF l_color = ′red′

THEN ...

ELSIF l_color = ′blue′ THEN

Page 15: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

...

ELSIF l_color = ′black′ THEN

...

-- Good CASE l_color

WHEN ′red′ THEN ... WHEN ′blue′ THEN ...

WHEN ′black′ THEN ...

END

- Use CASE rather than DECODE. DECODE is SQL function which cannot be used in PL/SQL.

- Always use COALESCE instead of NVL if the second parameter of the NVL function is a function

call or a SELECT statement. The NVL function always evaluates both parameters before deciding

which one to use. This can be harmful if parameter 2 is either a function call or a select

statement, as it will be executed regardless of whether parameter 1 contains a NULL value

or not.

-- Bad SELECT NVL(dummy, function_call()) FROM dual;

-- Good SELECT COALESCE(dummy, function_call()) FROM dual;

- Always use CASE instead of NVL2 if parameter 2 or 3 of NVL2 is either a function call or a SELECT

statement.

Some Built-in Utilities

PLSQL_OPTIMIZE_LEVEL The PLSQL_OPTIMIZE_LEVEL parameter was introduced in 10g to control how much optimization the

compiler performs. There are 4 levels:

- 0: Code will compile and run in a similar way to 9i and earlier. New actions of BINARY_INTEGER

and PLS_INTEGER lost.

- 1: Performs a variety of optimizations, including elimination of unnecessary computations and

exceptions. Does not alter source order.

- 2: Performs additional optimizations, including reordering source code if necessary. This is the

default setting in 10g and 11g. The optimizer may inline code automatically.

- 3: New in 11g.

The optimization level associated with the library unit (plsql code) is visible using the views

(USER_PLSQL_OBJECT_SETTINGS, ALL_PLSQL_OBJECT_SETTINGS or DBA_PLSQL_OBJECT_SETTINGS).

Page 16: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

select name, type, plsql_optimize_level from user_plsql_object_settings;

To change the value of the PLSQL_OPTIMIZE_LEVEL, issue the following statement…

ALTER SESSION SET plsql_optimize_level=0;

ALTER SESSION SET plsql_optimize_level=1; ALTER SESSION SET plsql_optimize_level=2;

ALTER SESSION SET plsql_optimize_level=3;

PLSQL_WARNINGS Compiler warnings were introduced in 10g to provide programmers with indications of possible code

improvements. The PLSQL_WARNING parameter can be set using ALTER SYSTEM or ALTER SESSION

commands or the DBMS_WARNING package.

-- Disable warnings in current session

ALTER SESSION SET PLSQL_WARNINGS='DISABLE:ALL'; EXEC DBMS_WARNING.set_warning_setting_string('DISABLE:ALL', 'SESSION');

-- Enable warnings in current session ALTER SESSION SET PLSQL_WARNINGS='ENABLE:ALL';

EXEC DBMS_WARNING.set_warning_setting_string('ENABLE:ALL', 'SESSION');

The warning level associated with the library unit is visible using the

ALL/USER/DBA_PLSQL_OBJECT_SETTINGS and ALL/USER/DBA_WARNING_SETTINGS views.

SELECT name, plsql_warnings FROM user_plsql_object_settings;

SELECT object_name, warning, setting FROM user_warning_settings;

PLSQL_DEBUG

The parameter PLSQL_DEBUG specifies whether or not PL/SQL library units will be compiled for

debugging. Its value can be true or false, and can be modified by ALTER SESSION or ALTER SYSTEM

command.

Please note that when PLSQL_DEBUG is set to true, PL/SQL library units will always compiled

INTEPRETED in order to be debuggable.

Native Compilation PL/SQL code is interpreted by default. Prior to 11g, native compilation converts PL/SQL to Proc*C, which

is then compiled in shared libraries. As a result, the parameter plsql_native_library_dir should be set to

store the C libraries. In Oracle 11g, PL/SQL native compilation requires no C compiler. By setting the

PLSQL_CODE_TYPE to the value of NATIVE, the PL/SQL code is compiled directly to machine code and

Page 17: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

stored in the SYSTEM tablespace. When the code is called, it is loaded into shared memory, making it

accessible for all sessions in that instance. The (USER/ALL/DBA)_PLSQL_OBJECT_SETTINGS views include

the current PLSQL_CODE_TYPE setting for each PL/SQL object.

Please note that native compilation will only improve the speed of procedure code, but has little effect

on the performance of SQL. When code performs lots of mathematical operations, native compilation

can produce considerable performance improves.

Set the parameter PLSQL_NATIVE_LIBRARY_DIR in the database with version earlier than 11g…

-- Prior to 11g, set the parameter PLSQL_NATIVE_LIBRARY_DIR first -- No need in 11g CONN system/password AS SYSDBA

ALTER SYSTEM SET plsql_native_library_dir = '/u01/app/oracle/admin/DB10G/native';

Set the parameter PLSQL_CODE_TYPE in session level…

ALTER SESSION SET plsql_code_type = 'INTERPRETED'; ALTER SESSION SET plsql_code_type = 'NATIVE';

Query the code compilation type…

select name, plsql_code_type from user_plsql_object_settings;

Conditional Compilation Conditional compilation was introduced in 10g to allow PL/SQL source code to be tailored to specific

environments using compilation directives. The PLSQL_CCFLAGS clauses is used to set the compiler flags,

and the compiler flags are identified by the “$$” prefix in the PL/SQL code. Conditional control is

provided by the $IF-$THEN-$ELSE syntax. The database source (can be viewed through the view

user_source) contains all the directives, but the post-processed source is displayed using the

DBMS_PREPROCSSOR package.

Set the parameter PLSQL_CCFGAS at code unit level, session level and system level…

ALTER PROCEDURE debug COMPILE PLSQL_CCFLAGS = 'debug_on:TRUE, show_date:TRUE' REUSE SETTINGS;

ALTER SESSION SET PLSQL_CCFLAGS = 'max_sentence:100';

ALTER SYSTEM SET PLSQL_CCFLAGS = 'VARCHAR2_SIZE:100, DEF_APP_ERR:-20001';

Treat different Oracle versions…

$IF dbms_db_version.ver_le_10 $THEN

Page 18: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

-- version 10 and earlier code $ELSIF dbms_db_version.ver_le_11 $THEN -- version 11 code $ELSE

-- version 12 and later code $END

Print the post-processed source code…

BEGIN

DBMS_PREPROCESSOR.print_post_processed_source ( object_type => 'PROCEDURE',

schema_name => USER, object_name => 'DEBUG');

END;

/

DML Error Logging By default, when a DML (update, delete, insert, merge) statement fails the whole statement is rolled

back, regardless of how many rows were processed successfully before the error was detected. Before

Oracle 10.2, the only way around this issue was to process each row individually, preferably with a bulk

operation using a FORALL loop with the SAVE EXCEPTIONS clause. In Oracle 10.2, the DML error logging

feature has been introduced to solve this problem. Adding the appropriate LOG ERRORS clause on to

most INSERT, UPDATE, MERGE and DELETE statements enables the operations to complete, regardless

of errors. Exceptional rows are added to a specially-created error table for further investigation.

There are two components to DML error logging as follows:

- LOG ERRORS clause to DML statements; and

- DBMS_ERRLOG package for managing error tables

Create error table for the “DML” table…

BEGIN

DBMS_ERRLOG.CREATE_ERROR_LOG(

dml_table_name => 'TGT', --<-- required err_log_table_name => 'TGT_ERRORS' --<-- optional ); END;

/

Specify the LOG ERRORS clause in the DML statement…

INSERT INTO tgt SELECT * FROM src

LOG ERRORS INTO tgt_errors ('INSERT..SELECT..SRC')

Page 19: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

REJECT LIMIT UNLIMITED;

Use contexts to store global data A context is a set of application-defined attributes associated with a namespace. Context attributes can

be read by the SYS_CONTEXT function, but must be set by the package specified when the context is

created. Consider using the “ACCESSED GLOBALLY” clause on the context to make the context

information available to all session. The context values set in the session can be viewed in the table

SESSION_CONTEXT.

Create a context “GLOBAL_CONTEXT” and the context attribute values should be set in the package

“GLOBAL_CONTEXT_API”…

CREATE OR REPLACE CONTEXT global_context USING global_context_api;

The package that used to set the context value…

CREATE OR REPLACE PACKAGE BODY global_context_api IS

-- ----------------------------------------------------------------- PROCEDURE set_parameter (p_name IN VARCHAR2,

p_value IN VARCHAR2) IS -- ----------------------------------------------------------------- BEGIN

DBMS_SESSION.set_context('global_context', p_name, p_value); END set_parameter;

-- ----------------------------------------------------------------- ...

Set the context value and retrieve the context value…

global_context_api.set_parameter('audit_on','N');

DBMS_OUTPUT.put_line('audit_on: ' || SYS_CONTEXT('global_context', 'audit_on'));

DBMS_APPLICATION_INFO The DBMS_APPLICATION_INFO package allows programs to add information to the V$SESSION and

V$SESSION_LONGOPS views. It can also be used to register long operations which useful for monitoring

the progress of jobs.

Monitor the PL/SQL block execution via V$SESSION…

BEGIN

DBMS_APPLICATION_INFO.set_module( module_name => 'module_action.sql',

Page 20: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

action_name => 'Starting');

DBMS_APPLICATION_INFO.set_client_info(client_info => 'Part of PL/SQL tuning demo.');

FOR i IN 1 .. 60 LOOP -- Update the current action. DBMS_APPLICATION_INFO.set_action(action_name => 'Processing row ' || i);

-- Do some work... DBMS_LOCK.sleep(1);

END LOOP;

DBMS_APPLICATION_INFO.set_action(action_name => 'Finished');

END; /

-- query in another session SELECT sid, serial#, module, action, client_info

FROM v$session

WHERE module = 'module_action.sql';

Monitor time consuming operation via V$SESSION_LONGOPS…

DECLARE

l_rindex PLS_INTEGER; l_slno PLS_INTEGER;

l_totalwork NUMBER;

l_sofar NUMBER; l_obj PLS_INTEGER;

BEGIN l_rindex := DBMS_APPLICATION_INFO.set_session_longops_nohint; l_sofar := 0;

l_totalwork := 100;

WHILE l_sofar < 100 LOOP -- Do some work

DBMS_LOCK.sleep(0.5);

l_sofar := l_sofar + 1;

DBMS_APPLICATION_INFO.set_session_longops( rindex => l_rindex, slno => l_slno,

op_name => 'BATCH_LOAD',

target => l_obj, context => 0,

sofar => l_sofar, totalwork => l_totalwork,

target_desc => 'BATCH_LOAD_TABLE', units => 'rows');

END LOOP;

END;

Page 21: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

/

-- query in another session SELECT opname,

target_desc, sofar,

totalwork,

units FROM v$session_longops

WHERE opname = 'BATCH_LOAD';

DBMS_SESSION Many applications manage user access internally and log into the database using a single user, which

makes identifying who is doing what difficult. The DBMS_SESSION package allows to set the

CLIENT_IDENTIFIER column of the V$SESSION view. The client identifier is also included in the audit trail.

-- in session 1

EXEC DBMS_SESSION.set_identifier(client_id => 'fang_test');

-- in session 2 EXEC DBMS_SESSION.set_identifier(client_id => 'fang_test');

-- query the v$session

select * from v$session where client_identifier='fang_test';

DBMS_PROFILER The DBMS_PROFILER package was introduced in Oracle 8i to make identification of performance

bottlenecks in PL/SQL easier. It records the number of executions and the elapsed time for each line of

code, not the execution order of the code.

DBMS_TRACE The DBMS_TRACE package records the execution order of PL/SQL, which may help to detect unusual

behavior not visible in the profiler results captured by DBMS_PROFILER.

Use DBMS_TRACE.set_plsql_trace for tracing…

BEGIN

DBMS_TRACE.set_plsql_trace (DBMS_TRACE.trace_all_calls); trace_test(p_loops => 100);

DBMS_TRACE.clear_plsql_trace;

DBMS_TRACE.set_plsql_trace (DBMS_TRACE.trace_all_sql); trace_test(p_loops => 100); DBMS_TRACE.clear_plsql_trace;

Page 22: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

DBMS_TRACE.set_plsql_trace (DBMS_TRACE.trace_all_lines); trace_test(p_loops => 100); DBMS_TRACE.clear_plsql_trace; END;

/

Query table PLSQL_TRACE_RUNS and PLSQL_TRACE_EVENTS to view trace results…

SELECT r.runid, TO_CHAR(r.run_date, 'DD-MON-YYYY HH24:MI:SS') AS run_date,

r.run_owner FROM plsql_trace_runs r

ORDER BY r.runid;

SELECT e.runid, e.event_seq,

TO_CHAR(e.event_time, 'DD-MON-YYYY HH24:MI:SS') AS event_time, e.event_unit_owner,

e.event_unit,

e.event_unit_kind, e.proc_line,

e.event_comment FROM plsql_trace_events e

WHERE e.runid = 3

ORDER BY e.runid, e.event_seq;

Some Traps

Pipelined table function and cardinality By default, the cardinality of pipelined table functions is based on the block size, so joining operations

can lead to performance issues.

Create a pipelined table function “GET_TAB”…

CREATE TYPE t_tf_row AS OBJECT ( id NUMBER,

description VARCHAR2(50) );

/

CREATE TYPE t_tf_tab IS TABLE OF t_tf_row;

/

CREATE OR REPLACE FUNCTION get_tab RETURN t_tf_tab PIPELINED AS BEGIN

FOR i IN 1 .. 100 LOOP

PIPE ROW (t_tf_row(i, 'Description for ' || i));

Page 23: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

END LOOP;

RETURN;

END;

/

Query the execution plan…

set autotrace trace explain

select * from table(get_tab);

Execution Plan

---------------------------------------------------------- Plan hash value: 3023735445

--------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 8168 | 16336 | 24 (0)| 00:00:01 |

| 1 | COLLECTION ITERATOR PICKLER FETCH| GET_TAB | | | | | ---------------------------------------------------------------------------------------------

set autotrace off

Please note that the ROWS returned shown in the execution plan is 8168 while the actual row returned

by the function GET_TAB is 100! This will lead to performance issue if join the rows returned by this

table function with other tables.

There are several ways to resolve this issue; the first one is to use the undocumented hint “cardinality”

(available since Oracle 9i) as follows,

SQL> select /*+cardinality(100)*/ * from TABLE(get_tab);

Execution Plan ---------------------------------------------------------- Plan hash value: 3023735445

--------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 100 | 200 | 24 (0)| 00:00:01 |

| 1 | COLLECTION ITERATOR PICKLER FETCH| GET_TAB | | | | | ---------------------------------------------------------------------------------------------

In Oracle 10g and above, a new undocumented hint “opt_estimate” can be used. This hint seems

doesn’t work that well as “cardinality”. See the example below,

select /*+ opt_estimate(table, t, scale_rows=0.01*/ * from TABLE(get_tab) t;

Page 24: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

Execution Plan ---------------------------------------------------------- Plan hash value: 3023735445

--------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 8168 | 16336 | 24 (0)| 00:00:01 | | 1 | COLLECTION ITERATOR PICKLER FETCH| GET_TAB | | | | |

---------------------------------------------------------------------------------------------

To use this hint, the scale_rows needs to be set correctly, which is calculated by the function of

round(actual rows/8168, 2) which is 0.01 in this case. However, seen from the execution plan the ROWS

returned is still 8168! So use this hint with caution.

In Oracle 11.1, another new hint “dynamic_sampling” was introduced. The difference between this one

and the two mentioned above is that this new hint is documented. That’s to say, this hint can be used

safely.

Besides taking advantage of Oracle hints, Oracle 10g also introduced a new feature called Extensible

Optimizer which can be used to tell the optimizer wheat the cardinality should be in a supported

manner. The disadvantage of using extensible optimizer is that it is more complex than hints.

First, need to change the definition of the function “GET_TAB” to add one parameter…

CREATE OR REPLACE FUNCTION get_tab (p_cardinality IN INTEGER DEFAULT 1)

RETURN t_tf_tab PIPELINED AS BEGIN

FOR i IN 1 .. 100 LOOP PIPE ROW (t_tf_row(i, 'Description for ' || i));

END LOOP;

RETURN;

END; /

Create one type “T_PTF_STATS” to implement some ODCI interface functions…

CREATE OR REPLACE TYPE t_ptf_stats AS OBJECT (

dummy INTEGER,

STATIC FUNCTION ODCIGetInterfaces (

p_interfaces OUT SYS.ODCIObjectList ) RETURN NUMBER,

STATIC FUNCTION ODCIStatsTableFunction (

p_function IN SYS.ODCIFuncInfo, p_stats OUT SYS.ODCITabFuncStats,

Page 25: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

p_args IN SYS.ODCIArgDescList,

p_cardinality IN INTEGER ) RETURN NUMBER

);

/

CREATE OR REPLACE TYPE BODY t_ptf_stats AS STATIC FUNCTION ODCIGetInterfaces (

p_interfaces OUT SYS.ODCIObjectList ) RETURN NUMBER IS

BEGIN

p_interfaces := SYS.ODCIObjectList( SYS.ODCIObject ('SYS', 'ODCISTATS2')

); RETURN ODCIConst.success;

END ODCIGetInterfaces;

STATIC FUNCTION ODCIStatsTableFunction (

p_function IN SYS.ODCIFuncInfo, p_stats OUT SYS.ODCITabFuncStats,

p_args IN SYS.ODCIArgDescList, p_cardinality IN INTEGER

) RETURN NUMBER IS

BEGIN p_stats := SYS.ODCITabFuncStats(p_cardinality);

RETURN ODCIConst.success; END ODCIStatsTableFunction;

END;

/

Associate the function “GET_TAB” with the type “T_PTF_STATS”…

ASSOCIATE STATISTICS WITH FUNCTIONS get_tab USING t_ptf_stats;

Then the SQL explain plan shows the row count returned by the function is right…

SQL> select * from table(get_tab(100));

Execution Plan ---------------------------------------------------------- Plan hash value: 3023735445

--------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 100 | 200 | 24 (0)| 00:00:01 | | 1 | COLLECTION ITERATOR PICKLER FETCH| GET_TAB | | | | |

---------------------------------------------------------------------------------------------

Page 26: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

DBMS_RANDOM DBMS_RANDOM is usually used to generate a random value. However, if don’t use this package with

care, the values generated by this package may be not random. Below is an example…

Suppose there is one table name T which has one column of data type VARCHAR2. What’s more, there is

one unique constraint on this column. Since the system doesn’t care the value of the string values as

long as they are unique in the table, package DBMS_RANDOM can be used. Below is one PL/SQL

function to generate the random string value,

CREATE OR REPLACE FUNCTION GET_NEXT_STR RETURN VARCHAR2

IS V_SEED VARCHAR2(50);

BEGIN SELECT TO_CHAR(SYSTIMESTAMP, 'ddmmyyyyHH24MMSSFF') INTO V_SEED FROM DUAL;

DBMS_RANDOM.SEED(V_SEED);

RETURN DBMS_RANDOM.STRING('A', 20);

END GET_NEXT_STR;

Before getting down to using this function in the table insertion SQL statement, perform a simple test to

see what the values are generated…

set serveroutput on

BEGIN FOR I IN 1..10

LOOP

DBMS_OUTPUT.PUT_LINE(GET_NEXT_STR); END LOOP;

END; And the results are like below…

AwPUykNKErDexsElUnwC

snKBvcxsTUiMSLWuMCgo

snKBvcxsTUiMSLWuMCgo

snKBvcxsTUiMSLWuMCgo

snKBvcxsTUiMSLWuMCgo

snKBvcxsTUiMSLWuMCgo

zNuLksgAvpBiSqXGqCeA

zNuLksgAvpBiSqXGqCeA

zNuLksgAvpBiSqXGqCeA

zNuLksgAvpBiSqXGqCeA

What a surprise! The values generated by the function are not unique. The problem lies in the function

GET_NEXT_STR uses the current timestamp as the SEED for the random function. Due to the precise of

the timestamp and the fast execution speed of CPU, the seed value may be the same for several loops.

That’s why the “random” values returned by the DBMS_RANDOM are not random. To resolve this issue,

don’t use the timestamp as the seed, use the seed generated by the system automatically.

Page 27: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

The literal string length limit in SQL statement The maximum string length can be used in SQL statement is 4000 bytes while this value can be increased

up to 32767 in PL/SQL.

See below for some tests about the maximum string length supported in SQL select clause…

SQL> select length(rpad('A', 3999, '*')) from dual;

LENGTH(RPAD('A',3999,'*')) -------------------------- 3999

SQL> select length(rpad('A', 4000, '*')) from dual; LENGTH(RPAD('A',4000,'*'))

-------------------------- 4000

SQL> select length(rpad('A', 4001, '*')) from dual; LENGTH(RPAD('A',4001,'*'))

-------------------------- 4000

SQL> select length(rpad('A', 40001, '*')) from dual; LENGTH(RPAD('A',40001,'*'))

--------------------------- 4000

The test result shows that the maximum string length can be supported in SQL select statement is 4000.

Even use the RPAD function to construct a string with length larger than 4000, the function LENGTH still

return 4000.

If reference one function which returns a string whose length larger than 4000, there will be an error

raised. See the example below for illustration…

SQL> CREATE OR REPLACE FUNCTION test_varchar2_max_length RETURN varchar2 AS

2 BEGIN

3 return RPAD('A', 4001, '*'); 4 END;

5 /

Function created.

SQL> select test_varchar2_max_length from dual;

select test_varchar2_max_length from dual *

ERROR at line 1:

ORA-06502: PL/SQL: numeric or value error: character string buffer too small ORA-06512: at "FRANK.TEST_VARCHAR2_MAX_LENGTH", line 3

SQL>

Page 28: PL/SQL Programming Tips - cnblogs.comfiles.cnblogs.com/files/fangwenyu/PLSQL_Programming_Tips.pdf · By Yu, Fang (franky.yu@163.com) Naming Conventions The following tables will illustrate

--------------------------------------------- By Yu, Fang ([email protected])

To resolve this issue, the return type of the function “test_varchar2_max_length” needs to be changed to

CLOB or some collection type.