Skip Headers
Oracle® Database PL/SQL Language Reference
11g Release 2 (11.2)

Part Number E10472-02
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

2 PL/SQL Language Fundamentals

This chapter explains these aspects of the PL/SQL language:

Character Sets

PL/SQL supports two character sets:

Database Character Set

PL/SQL uses the database character set for identifiers (which are described in "Identifiers") and to store data.

The database character set consists of these characters:

  • Letters A through Z and a through z

    Corresponding uppercase and lowercase letters are equivalent—for example, A is equivalent to a—except in character literals and string literals.

  • Digits 0 through 9

  • Symbols in Table 2-1

  • Whitespace characters tab, space, and carriage return

Table 2-1 Symbols in Database Character Set

Symbol Name

(

Left parenthesis

)

Right parenthesis

[

Left bracket

]

Right bracket

<

Left angle bracket

>

Right angle bracket

{

Left brace

}

Right brace

+

Plus sign

-

Hyphen or minus sign

*

Asterisk

/

Slash

=

Equal sign

,

Comma

;

Semicolon

:

Colon

.

Period

!

Exclamation point

?

Question mark

'

Apostrophe or single quotation mark

"

Quotation mark or double quotation mark

~

Tilde

^

Caret

@

At sign

%

Percent sign

#

Number sign

$

Dollar sign

&

Ampersand

_

Underscore

|

Vertical bar


To specify the database character set, use the CHARACTER SET clause of the CREATE DATABASE statement. For information about this statement, see Oracle Database SQL Language Reference.

National Character Set

PL/SQL uses the national character set to represent languages that have thousands of characters, each of which requires two or three bytes (Japanese, for example). The national character set represents data as Unicode, using either the AL16UTF16 or UTF8 encoding.

Table 2-2 compares AL16UTF16 and UTF8 encodings. For maximum reliability, Oracle recommends using the default AL16UTF16 encoding wherever practical.

Table 2-2 Comparison of AL16UTF16 and UTF8 Encodings

Encoding Character Size (Bytes) Advantage Disadvantage

AL16UTF16 (default)

2

Easy to calculate string lengths, which you must do to avoid truncation errors when mixing programming languages.

Strings composed mostly of ASCII or EBCDIC characters take more space than necessary.

UTF8

1, 2, or 3

If most characters use only one byte, you can fit more characters into a variable or table column.

Possibility of truncation errors when transferring the data to a buffer measured in bytes.


To determine how many bytes a Unicode string needs, use the SQL function LENGTHB. For information about this statement, see Oracle Database SQL Language Reference.

To specify the national character set, use the NATIONAL CHARACTER SET clause of the CREATE DATABASE statement. For information about this statement, see Oracle Database SQL Language Reference.

See Also:

Lexical Units

The lexical units of PL/SQL are its smallest individual components. They fall into these catagories:

You cannot embed whitespace or punctuation characters inside lexical units (except string literals and comments).

Example 2-1 shows what happens when you embed a space in a delimiter (the assignment operator).

Example 2-1 Delimiter with Embedded Space

BEGIN
  count := count + 1;   -- correct
  count : = count + 1;  -- incorrect
END;
/
 

Result:

count : = count + 1;  -- incorrect
        *
ERROR at line 3:
ORA-06550: line 3, column 9:
PLS-00103: Encountered the symbol ":" when expecting one of these:
:= . ( @ % ;

You can put whitespace characters between lexical units, which often makes your source code easier to read, as in Example 2-2.

Example 2-2 Whitespace Characters Improving Source Code Readability

DECLARE
  x    NUMBER := 10;
  y    NUMBER := 5;
  max  NUMBER;
BEGIN
  IF x>y THEN max:=x;ELSE max:=y;END IF;  -- correct but hard to read
  
  -- Easier to read:
  
  IF x > y THEN
    max:=x;
  ELSE
    max:=y;
  END IF;
END;
/

Topics:

Delimiters

A delimiter is a character, or character combination, that has a special meaning in PL/SQL. Table 2-3 summarizes the PL/SQL delimiters.

Table 2-3 PL/SQL Delimiters

Delimiter Meaning

+

Addition operator

:=

Assignment operator

=>

Association operator

%

Attribute indicator

'

Character string delimiter

.

Component indicator

||

Concatenation operator

/

Division operator

**

Exponentiation operator

(

Expression or list delimiter (begin)

)

Expression or list delimiter (end)

:

Host variable indicator

,

Item separator

<<

Label delimiter (begin)

>>

Label delimiter (end)

/*

Multiline comment delimiter (begin)

*/

Multiline comment delimiter (end)

*

Multiplication operator

"

Quoted identifier delimiter

..

Range operator

=

Relational operator (equal)

<>

Relational operator (not equal)

!=

Relational operator (not equal)

~=

Relational operator (not equal)

^=

Relational operator (not equal)

<

Relational operator (less than)

>

Relational operator (greater than)

<=

Relational operator (less than or equal)

>=

Relational operator (greater than or equal)

@

Remote access indicator

--

Single-line comment indicator

;

Statement terminator

-

Subtraction or negation operator


Identifiers

Identifiers name PL/SQL objects, which include:

  • Constants

  • Cursors

  • Exceptions

  • Keywords

  • Labels

  • Packages

  • Reserved words

  • Subprograms

  • Variables

  • Types

You must separate adjacent identifiers by one or more spaces or a punctuation character.

Example 2-3 shows what happens when the identifiers END and IF are not separated.

Example 2-3 Identifiers Not Separated by Space or Punctuation

BEGIN
  IF x > y THEN high := x; END IF;  -- correct
  IF x > y THEN high := x; ENDIF;   -- incorrect
END;
/
 

Result:

END;
   *
ERROR at line 4:
ORA-06550: line 4, column 4:
PLS-00103: Encountered the symbol ";" when expecting one of these:
if

PL/SQL is case-insensitive for identifiers. For example, these identifiers are the same:

lastname
LastName
LASTNAME

Every character in an identifier, alphabetic or not, is significant. For example, these identifiers are different:

lastname
last_name

Topics:

Reserved Words and Keywords

Reserved words and keywords are identifiers that have special meaning in PL/SQL.

You cannot use reserved words as ordinary user-defined identifiers. You can use keywords as ordinary user-defined identifiers, and you can use reserved words as quoted user-defined identifiers, but neither practice is recommended.

For lists of PL/SQL reserved words and keywords, see Table D-1 and Table D-2, respectively.

Predefined Identifiers

Predefined identifiers are declared in the predefined package STANDARD. An example of a predefined identifier is the exception INVALID_NUMBER. You can use predefined identifiers as user-defined identifiers, but it is not recommended. Your local declaration overrides the global declaration (see "Scope and Visibility of Identifiers").

For a list of predefined identifiers, query the static data dictionary view *_TYPES. For example:

SELECT TYPE_NAME, PREDEFINED FROM ALL_TYPES;

User-Defined Identifiers

PL/SQL lets you define identifiers. An ordinary (as opposed to quoted) user-defined identifier:

  • Begins with a letter

  • Can include digits and these symbols:

    • Dollar sign ($)

    • Number sign (#)

    • Underscore (_)

  • Has at most 30 characters

Examples of acceptable ordinary user-defined identifiers:

X
t2
phone#
credit_limit
LastName
oracle$number
money$$$tree
SN##
try_again_

Examples of unacceptable ordinary user-defined identifiers:

mine&yours
debit-amount
on/off
user id

Tip:

Make user-defined identifiers meaningful. For example, the meaning of cost_per_thousand is obvious, but the meaning of cpt is not.

Quoted Identifiers

A quoted identifier is a user-defined identifier that is enclosed in double quotation marks. Between the double quotation marks, any characters are allowed except double quotation marks. For example, these identifiers are acceptable:

"X+Y"
"last name"
"on/off switch"
"employee(s)"
"*** header info ***"

The maximum size of a quoted identifier is 30 characters (excluding the double quotation marks).

Literals

A literal is a value that is not represented by an identifier or an expression.

Topics:

For syntax diagrams of literals, see "Literal".

Numeric Literals

A numeric literal can have a sign (+ or -) and can be either an integer or a real number.

An integer literal is a whole number without a decimal point. For example:

030
6
-14
+32767

A real literal is a whole or fractional number with a decimal point. For example:

6.6667
0.0
-12.0
3.14159
+8300.00
.5
25.

In PL/SQL, numbers such as 12.0 and 25. are real.

If you add the suffix d or D to a numeric literal, its data type is BINARY_DOUBLE; if you add the suffix f or F, its data type is BINARY_FLOAT. For example:

2.0f
2D

You can write numeric literals in scientific notation, using e or E. For example:

2E5
1.0E-7
3.14159e0
-1E38
-9.5e-3

aEb means a(10b)—or, in PL/SQL, a*(10**b). Therefore:

5E3 = 5 * 10**3 = 5 * 1000 = 5000

For information about numeric data types, see "Predefined PL/SQL Numeric Data Types and Subtypes".

Character Literals

A character literal is a single character enclosed in single quotation marks. For example:

'Z'
'%'
'7'
' '
'z'
'('

A character literal has the data type CHAR. For information about the CHAR data type, see "CHAR and VARCHAR2 Data Types".

PL/SQL is case-sensitive for character literals. For example, the literals 'Z' and 'z' are different.

The character literals '0' through'9' are not equivalent to the integer literals 0 through 9, but you can use them in arithmetic expressions, because PL/SQL converts them to integers.

String Literals

A string literal is a string of zero or more characters, enclosed in single quotation marks. For example:

'Hello, world!'
'XYZ Corporation'
'10-NOV-91'
'He said, "Life is like licking honey from a thorn."'
'$1,000,000'

A string literal has the data type CHAR. For information about the CHAR data type, see "CHAR and VARCHAR2 Data Types".

A string literal with zero characters is a null string. It has the value NULL.

PL/SQL is case-sensitive for string literals. For example, these literals are different:

'baker'
'Baker'

Blanks are significant in string literals, including leading and trailing blanks. For example, these literals are different:

'abc'
' abc'
'abc '
' abc '

However, PL/SQL trims trailing blanks when you assign a string literal to a CHAR column.

To put an apostrophe or single quotation mark (') inside a string literal, you have two choices:

  • Use two adjacent single quotation marks (which is different from using one double quotation mark):

    'I''m a string, you''re a string.'
    
  • Define your own delimiter character for the string:

    q'delimiter_character string delimiter_character'
    

    Where delimiter_character is not present in string. For example:

    q'!I'm a string, you're a string.!'
    

    For Unicode string literals, use nq instead of q. For more information about the Unicode strings, see Oracle Database Globalization Support Guide.

BOOLEAN Literals

ABOOLEAN literal is the predefined value TRUE, FALSE, or NULL. NULL represents an unknown value.

For information about the BOOLEAN data type, see "Predefined PL/SQL BOOLEAN Data Type".

Datetime and Interval Literals

The syntax of a datetime or interval literal depends on its data type. Example 2-4 shows some datetime and interval literals. For more information, see "Predefined PL/SQL Datetime and Interval Data Types".

Example 2-4 Datetime and Interval Literals

DECLARE
  d1 DATE      := DATE '1998-12-25';
  t1 TIMESTAMP := TIMESTAMP '1997-10-22 13:01:01';
  
  t2 TIMESTAMP WITH TIME ZONE :=
  TIMESTAMP '1997-01-31 09:26:56.66 +02:00';
  
  -- Three years and two months
  -- For greater precision, use the day-to-second interval
 
  i1 INTERVAL YEAR TO MONTH := INTERVAL '3-2' YEAR TO MONTH;
 
  -- Five days, four hours, three minutes, two and 1/100 seconds
 
  i2 INTERVAL DAY TO SECOND := INTERVAL '5 04:03:02.01' DAY TO SECOND;
 
BEGIN
  NULL;
END;
/

Comments

The PL/SQL compiler ignores comments. Adding comments to your program can make it easier to read and understand. Typically, you use comments to describe the purpose and use of each code segment. You can also disable obsolete or unfinished pieces of code by turning them into comments.

Topics:

See Also:

"Comment"

Single-Line Comments

A single-line comment begins with -- and extends to the end of the line.

Caution:

Do not put a single-line comment in a PL/SQL block to be processed dynamically by an Oracle Precompiler program. The Oracle Precompiler program ignores end-of-line characters, which means that a single-line comment ends when the block ends.

Example 2-5 has three single-line comments.

Example 2-5 Single-Line Comments

DECLARE
  howmany     NUMBER;
  num_tables  NUMBER;
BEGIN
  -- Begin processing
  SELECT COUNT(*) INTO howmany
  FROM USER_OBJECTS
  WHERE OBJECT_TYPE = 'TABLE'; -- Check number of tables
  num_tables := howmany;       -- Compute another value
END;
/

While testing or debugging a program, you can disable a line of code by making it a comment. For example:

-- DELETE FROM employees WHERE comm_pct IS NULL

Multiline Comments

A multiline comment begins with /*, ends with */, and can span multiple lines.

Example 2-6 has two multiline comments. (The built-in SQL function TO_CHAR returns the character equivalent of its argument. For more information about TO_CHAR, see Oracle Database SQL Language Reference.)

Example 2-6 Multiline Comments

DECLARE
  some_condition  BOOLEAN;
  pi              NUMBER := 3.1415926;
  radius          NUMBER := 15;
  area            NUMBER;
BEGIN
  /* Perform some simple tests and assignments */
 
  IF 2 + 2 = 4 THEN
    some_condition := TRUE;
  /* We expect this THEN to always be performed */
  END IF;
 
  /* This line computes the area of a circle using pi,
  which is the ratio between the circumference and diameter.
  After the area is computed, the result is displayed. */
 
  area := pi * radius**2;
  DBMS_OUTPUT.PUT_LINE('The area is: ' || TO_CHAR(area));
END;
/
 

Result:

The area is: 706.858335

You can use multiline comment delimiters to "comment out" sections of code. When doing so, be careful not to cause nested multiline comments. One multiline comment cannot contain another multiline comment. However, a multiline comment can contain a single-line comment. For example, this causes a syntax error:

/*
  IF 2 + 2 = 4 THEN
    some_condition := TRUE;
  /* We expect this THEN to always be performed */
  END IF;
*/

This does not cause a syntax error:

/*
  IF 2 + 2 = 4 THEN
    some_condition := TRUE;
  -- We expect this THEN to always be performed
  END IF;
*/

Declarations

A declaration allocates storage space for a value of a specified data type, and names the storage location so that you can reference it. You must declare objects before you can reference them. Declarations can appear in the declarative part of any block, subprogram, or package.

Topics:

For information about declaring objects other than variables and constants, see the syntax of declare_section in "Block".

Variable Declarations

A variable declaration always specifies the name and data type of the variable. It can also specify an initial value and the NOT NULL constraint.

The name must be a valid user-defined identifier (see "User-Defined Identifiers").

The data type can be a SQL data type (such as CHAR, DATE, or NUMBER) or a PL/SQL-only data type (such as BOOLEAN or PLS_INTEGER). For information about data types, see Chapter 3, "PL/SQL Data Types".

Example 2-7 declares several variables.

Example 2-7 Variable Declarations

DECLARE
  part_number       NUMBER(6);     -- SQL data type
  part_name         VARCHAR2(20);  -- SQL data type
  in_stock          BOOLEAN;       -- PL/SQL-only data type
  part_price        NUMBER(6,2);   -- SQL data type
  part_description  VARCHAR2(50);  -- SQL data type
BEGIN
  NULL;
END;
/

For variable declaration syntax, see "Variable".

Constant Declarations

The information in "Variable Declarations" also applies to constant declarations, but a constant declaration has two more requirements: the keyword CONSTANT and the initial value of the constant. (The initial value of a constant is its permanent value.)

You can define constants of complex types that have no literal values or predefined constructors, by invoking a function that returns a filled-in value. For example, you can make a constant associative array this way.

Example 2-8 declares three constants.

Example 2-8 Constant Declarations

DECLARE
  credit_limit     CONSTANT REAL    := 5000.00;  -- SQL data type
  max_days_in_year CONSTANT INTEGER := 366;      -- SQL data type
  urban_legend     CONSTANT BOOLEAN := FALSE     -- PL/SQL-only data type;
BEGIN
  NULL;
END;
/

For constant declaration syntax, see "Constant".

Initial Values of Variables and Constants

In a variable declaration, the initial value is optional (the default is NULL). In a constant declaration, the initial value is required (and the constant can never have a different value).

The initial value is assigned to the variable or constant every time control passes to the block or subprogram that contains the declaration. If the declaration is in a package specification, the initial value is assigned to the variable or constant once for each session (whether the variable or constant is public or private).

To specify the initial value, use either the assignment operator (:=) or the keyword DEFAULT, followed by an expression. The expression can include previously declared constants and previously initialized variables.

Example 2-9 assigns initial values to the constant and variables that it declares. The initial value of area depends on the previously declared constant pi and the previously initialized variable radius.

Example 2-9 Variable and Constant Declarations with Initial Values

DECLARE
  hours_worked    INTEGER := 40;
  employee_count  INTEGER := 0;

  pi     CONSTANT REAL := 3.14159;
  radius          REAL := 1;
  area            REAL := (pi * radius**2);
BEGIN
  NULL;
END;
/

If you do not specify an initial value for a variable, assign a value to it before using it in any other context.

In Example 2-10, the variable counter has the initial value NULL, by default. As the example shows (using the "IS [NOT] NULL Operator") NULL is different from zero.

Example 2-10 Variable Initialized to NULL by Default

DECLARE
  counter INTEGER;  -- initial value is NULL by default
BEGIN
  counter := counter + 1;  -- NULL + 1 is still NULL
  
  IF counter IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('counter is NULL.');
  END IF;
END;
/
 

Result:

counter is NULL.

NOT NULL Constraint

A variable or constant declaration can specify the NOT NULL constraint, which prevents anyone from assigning a null value to the variable or constant.

A variable declaration that specifies NOT NULL must assign an initial value to the variable (because the default initial value for a variable is NULL).

PL/SQL subtypes NATURALN, POSITIVEN, and SIMPLE_INTEGER are predefined as NOT NULL. When declaring a variable of one of these subtypes, you can omit NOT NULL, and you must specify an initial value.

In Example 2-11, all four variables have the NOT NULL constraint.

Example 2-11 Variable Declaration with NOT NULL Constraint

DECLARE
  acct_id INTEGER(4) NOT NULL := 9999;
  a NATURALN                  := 9999;
  b POSITIVEN                 := 9999;
  c SIMPLE_INTEGER            := 9999;
BEGIN
  NULL;
END;
/

PL/SQL treats any zero-length string as a NULL value. This includes values returned by character functions and BOOLEAN expressions.

In Example 2-12, all of the variables are initialized to NULL.

Example 2-12 Variables Initialized to NULL Values

DECLARE
  null_string  VARCHAR2(80) := TO_CHAR('');
  address      VARCHAR2(80);
  zip_code     VARCHAR2(80) := SUBSTR(address, 25, 0);
  name         VARCHAR2(80);
  valid        BOOLEAN      := (name != '');
BEGIN
  NULL;
END;
/

To test for a NULL value, use the "IS [NOT] NULL Operator".

%TYPE Attribute

The %TYPE attribute lets you declare a data item to be of the same data type as a previously declared data item or database column. If the declaration of the referenced item changes, the declaration of the referencing item changes accordingly.

The syntax of the declaration is:

referencing_item referenced_item%TYPE;

For the kinds of data items that can be referencing and referenced items, see "%TYPE Attribute".

The referencing item inherits the following from the referenced item:

  • Data type

  • Constraints (unless the referenced item is a database column)

The referencing item does not inherit the initial value of the referenced item. Therefore, if the referencing item specifies or inherits the NOT NULL constraint, you must specify an initial value for it.

The %TYPE attribute is particularly useful when declaring variables to hold database values. The syntax for declaring a variable of the same type as a database column is:

variable_name table_name.column_name%TYPE;

In Example 2-13, the variable surname inherits the data type of the database column employees.last_name, which has a NOT NULL constraint. Because surname does not inherit the NOT NULL constraint, its declaration does not need an initial value.

Example 2-13 Declaring Variable of Same Type as Database Column

DECLARE
  surname  employees.last_name%TYPE;
BEGIN
  DBMS_OUTPUT.PUT_LINE('surname=' || surname);
END;
/

Result:

surname=

In Example 2-14, the variable surname inherits the data type and the NOT NULL constraint of the variable name. Because surname does not inherit the initial value of name, its declaration needs an initial value.

Example 2-14 Declaring Variable of Same Type as Another Variable

DECLARE
  name     VARCHAR(25) NOT NULL := 'Smith';
  surname  name%TYPE := 'Jones';
BEGIN
  DBMS_OUTPUT.PUT_LINE('name=' || name);
  DBMS_OUTPUT.PUT_LINE('surname=' || surname);
END;
/

Result:

name=Smith
surname=Jones

%ROWTYPE Attribute

The %ROWTYPE attribute lets you declare a record that represents a row of a database table or view: For every column of the row, the record has a field with the same name and data type. The record can store an entire row that is either selected from the table or view or fetched from a cursor.

The record fields do not inherit the constraints or initial values of the corresponding columns.

If the structure of the row changes, the structure of the record changes accordingly.

The syntax for declaring a record variable to hold a table row is:

variable_name table_name%ROWTYPE;

For more information about the syntax of %ROWTYPE, see "%ROWTYPE Attribute".

Example 2-15 creates a table, employees_temp, and then creates a record, emprec, that has a field for every column in the table. Each field (referenced by emprec.field_name) inherits the name and data type of the corresponding column, but not the constraints or initial value.

Example 2-15 Declaring Record that Represents Table Row

CREATE TABLE employees_temp (
  empid    NUMBER(6) NOT NULL PRIMARY KEY
  deptid   NUMBER(6) CONSTRAINT c_employees_temp_deptid
                     CHECK (deptid BETWEEN 100 AND 200),
  deptname VARCHAR2(30) := 'Sales'
);
 
DECLARE
  emprec  employees_temp%ROWTYPE;
BEGIN
  emprec.empid := NULL;  -- Null constraint not inherited
  emprec.deptid := 50;   -- Check constraint not inherited
  DBMS_OUTPUT.PUT_LINE ('emprec.deptname: ' || emprec.deptname);
                           -- Initial value not inherited
END;
/
 

Result:

emprec.deptname:

Example 2-16 declares a cursor, c1, which returns two columns of the departments table, and then creates a record, dept_rec, that has a field for each returned column.

Example 2-16 Declaring a Record that Represents a Subset of Table Columns

DECLARE
  CURSOR c1 IS
    SELECT department_id, department_name
    FROM departments;
  
  dept_rec c1%ROWTYPE;  -- Has 2 fields, department_id and department_name
  
BEGIN
  NULL;
END;
/

In Example 2-16, the record join_rec has four fields: employee_id, email, and manager_id (which correspond to columns in the employees table) and location_id (which correspond to a column in the departments table).

Example 2-17 Declaring a Record that Represents a Row from a Join

DECLARE
  CURSOR c2 IS
    SELECT employee_id, email, employees.manager_id, location_id
    FROM employees, departments
    WHERE employees.department_id = departments.department_id;
  
  join_rec  c2%ROWTYPE;  -- includes columns from two tables
  
BEGIN
  NULL;
END;
/

Note:

A %ROWTYPE declaration cannot include an initial value. For information about assigning values to records, see "Assignments to Records".

References to Identifiers

When referencing an identifier, you use a name that is either simple, qualified, remote, or both qualified and remote.

The simple name of an identifier is the name in its declaration. For example:

DECLARE
  a INTEGER;  -- Declaration
BEGIN
  a := 1;     -- Reference with simple name
END;
/

If an identifier is declared in a named PL/SQL unit, you can (and sometimes must) reference it with its qualified name. The syntax (called dot notation) is:

unit_name.simple_identifier_name

For example, if package p declares identifier a, you can reference the identifier with the qualified name p.a. The unit name also can (and sometimes must) be qualified. You must qualify an identifier when it is not visible (see "Scope and Visibility of Identifiers").

If the identifier names an object that is stored on a remote database, you must reference it with its remote name. The syntax is:

simple_identifier_name@link_to_remote_database

If the identifier is declared in a PL/SQL unit that is stored on a remote database, you must reference it with its qualified remote name. The syntax is:

unit_name.simple_identifier_name@link_to_remote_database

You can create synonyms for remote schema objects, but you cannot create synonyms for objects declared in PL/SQL subprograms or packages. To create a synonym, use the SQL statement CREATE SYNONYM, described in Oracle Database SQL Language Reference.

For information about how PL/SQL resolves ambiguous names, see Appendix B, "PL/SQL Name Resolution".

Scope and Visibility of Identifiers

The scope of an identifier is the region of a PL/SQL unit from which you can reference the identifier. The visibility of an identifier is the region of a PL/SQL unit from which you can reference the identifier without qualifying it. An identifier is local to the PL/SQL unit that declares it. If that unit has subunits, the identifier is global to them.

If a subunit redeclares a global identifier, then inside the subunit, both identifiers are in scope, but only the local identifier is visible. To reference the global identifier, the subunit must qualify it with the name of the unit that declared it. If that unit has no name, then the subunit cannot reference the global identifier.

A PL/SQL unit cannot reference identifiers declared in other units at the same level, because those identifiers are neither local nor global to the block.

Example 2-18 shows the scope and visibility of several identifiers. The first sub-block redeclares the global identifier a. To reference the global variable a, the first sub-block would have to qualify it with the name of the outer block—but the outer block has no name. Therefore, the first sub-block cannot reference the global variable a; it can reference only its local variable a. Because the sub-blocks are at the same level, the first sub-block cannot reference d, and the second sub-block cannot reference c.

Example 2-18 Scope and Visibility of Identifiers

-- Outer block:
DECLARE
  a CHAR;  -- Scope of a (CHAR) begins
  b REAL;    -- Scope of b begins
BEGIN
  -- Visible: a (CHAR), b
  
  -- First sub-block:
  DECLARE
    a INTEGER;  -- Scope of a (INTEGER) begins
    c REAL;       -- Scope of c begins
  BEGIN
    -- Visible: a (INTEGER), b, c
    NULL;
  END;          -- Scopes of a (INTEGER) and c end

  -- Second sub-block:
  DECLARE
    d REAL;     -- Scope of d begins
  BEGIN
    -- Visible: a (CHAR), b, d
    NULL;
  END;          -- Scope of d ends

-- Visible: a (CHAR), b
END;            -- Scopes of a (CHAR) and b end
/

Example 2-19 labels the outer block with the name outer. Therefore, after the sub-block redeclares the global variable birthdate, it can reference that global variable by qualifying its name with the block label. The sub-block can also reference its local variable birthdate, by its simple name.

Example 2-19 Qualifying a Redeclared Global Identifier with a Block Label

<<outer>>  -- label
DECLARE
  birthdate DATE := '09-AUG-70';
BEGIN
  DECLARE
    birthdate DATE := '29-SEP-70';
  BEGIN
    IF birthdate = outer.birthdate THEN
      DBMS_OUTPUT.PUT_LINE ('Same Birthday');
    ELSE
      DBMS_OUTPUT.PUT_LINE ('Different Birthday');
    END IF;
  END;
END;
/
 

Result:

Different Birthday

In Example 2-20, the procedure check_credit declares a variable, rating, and a function, check_rating. The function redeclares the variable. Then the function references the global variable by qualifying it with the procedure name.

Example 2-20 Qualifying an Identifier with a Subprogram Name

CREATE OR REPLACE PROCEDURE check_credit (limit NUMBER) AS
  rating NUMBER := 3;
  
  FUNCTION check_rating RETURN BOOLEAN IS
    rating  NUMBER := 1;
    over_limit  BOOLEAN;
  BEGIN
    IF check_credit.rating <= limit THEN  -- reference to global variable
      over_limit := FALSE;
    ELSE
      over_limit := TRUE;
      rating := limit;                    -- reference to local variable
    END IF;
    RETURN over_limit;
  END check_rating;
BEGIN
  IF check_rating THEN
    DBMS_OUTPUT.PUT_LINE
      ('Credit rating over limit (' || TO_CHAR(limit) || ').  '
      || 'Rating: ' || TO_CHAR(rating));
  ELSE
    DBMS_OUTPUT.PUT_LINE
      ('Credit rating OK.  ' || 'Rating: ' || TO_CHAR(rating));
  END IF;
END;
/
 
BEGIN
  check_credit(1);
END;
/
 

Result:

Credit rating over limit (1).  Rating: 3

You cannot declare the same identifier twice in the same PL/SQL unit. If you do, an error occurs when you reference the duplicate identifier, as Example 2-21 shows.

Example 2-21 Duplicate Identifiers in Same Scope

DECLARE
  id  BOOLEAN;
  id  VARCHAR2(5);  -- duplicate identifier
BEGIN
  id := FALSE;
END;
/
 

Result:

id := FALSE;
  *
ERROR at line 5:
ORA-06550: line 5, column 3:
PLS-00371: at most one declaration for 'ID' is permitted
ORA-06550: line 5, column 3:
PL/SQL: Statement ignored

You can declare the same identifier in two different units. The two objects represented by the identifier are distinct. Changing one does not affect the other, as Example 2-22 shows.

Example 2-22 Declaring the Same Identifier in Two Different Units

DECLARE
  PROCEDURE p
  IS
    x VARCHAR2(1);
  BEGIN
    x := 'a';  -- Assign the value 'a' to x
    DBMS_OUTPUT.PUT_LINE('In procedure p, x = ' || x);
  END;
 
  PROCEDURE q
  IS
    x VARCHAR2(1);
  BEGIN
    x := 'b';  -- Assign the value 'b' to x
    DBMS_OUTPUT.PUT_LINE('In procedure q, x = ' || x);
  END;
 
BEGIN
  p;
  q;
END;
/

Result:

In procedure p, x = a
In procedure q, x = b

In the same scope, give labels and subprograms unique names to avoid confusion and unexpected results.

In Example 2-23, echo is the name of both a block and a subprogram. Both the block and the subprogram declare a variable named x. In the subprogram, echo.x refers to the local variable x, not to the global variable x.

Example 2-23 Label and Subprogram with Same Name in Same Scope

<<echo>>
DECLARE
  x  NUMBER := 5;
  
  PROCEDURE echo AS
    x  NUMBER := 0;
  BEGIN
    DBMS_OUTPUT.PUT_LINE('x = ' || x);
    DBMS_OUTPUT.PUT_LINE('echo.x = ' || echo.x);
  END;
 
BEGIN
  echo;
END;
/
 

Result:

x = 0
echo.x = 0

Example 2-24 has two labels for the outer block, compute_ratio and another_label. The second label is used again in the inner block. In the inner block, another_label.denominator refers to the local variable denominator, not to the global variable denominator, which results in the error ZERO_DIVIDE.

Example 2-24 Block with Multiple and Duplicate Labels

<<compute_ratio>>
<<another_label>>
DECLARE
  numerator   NUMBER := 22;
  denominator NUMBER := 7;
BEGIN
  <<another_label>>
  DECLARE
    denominator NUMBER := 0;
  BEGIN
    DBMS_OUTPUT.PUT_LINE('Ratio with compute_ratio.denominator = ');
    DBMS_OUTPUT.PUT_LINE(numerator/compute_ratio.denominator);
 
    DBMS_OUTPUT.PUT_LINE('Ratio with another_label.denominator = ');
    DBMS_OUTPUT.PUT_LINE(numerator/another_label.denominator);
 
  EXCEPTION
    WHEN ZERO_DIVIDE THEN
      DBMS_OUTPUT.PUT_LINE('Divide-by-zero error: can''t divide '
        || numerator || ' by ' || denominator);
    WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE('Unexpected error.');
  END another_label;
END compute_ratio;
/
 

Result:

Ratio with compute_ratio.denominator =
3.14285714285714285714285714285714285714
Ratio with another_label.denominator =
Divide-by-zero error: cannot divide 22 by 0

Assigning Values to Variables

After declaring a variable, you can assign a value to it in these ways:

Topics:

For information about the FETCH statement, see "FETCH Statement".

Assigning Values to Variables with the Assignment Statement

To assign the value of an expression to a variable, use this form of the assignment statement:

variable_name := expression;

For the complete syntax of the assignment statement, see "Assignment Statement". For the syntax of an expression, see "Expression".

Example 2-25 declares several variables (specifying initial values for some) and then uses assignment statements to assign the values of expressions to them.

Example 2-25 Assigning Values to Variables with Assignment Statement

DECLARE  -- You can assign initial values here
  wages          NUMBER;
  hours_worked   NUMBER := 40;
  hourly_salary  NUMBER := 22.50;
  bonus          NUMBER := 150;
  country        VARCHAR2(128);
  counter        NUMBER := 0;
  done           BOOLEAN;
  valid_id       BOOLEAN;
  emp_rec1       employees%ROWTYPE;
  emp_rec2       employees%ROWTYPE;
  TYPE commissions IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
  comm_tab       commissions;
 
BEGIN  -- You can assign values here too
  wages := (hours_worked * hourly_salary) + bonus;
  country := 'France';
  country := UPPER('Canada');
  done := (counter > 100);
  valid_id := TRUE;
  emp_rec1.first_name := 'Antonio';
  emp_rec1.last_name := 'Ortiz';
  emp_rec1 := emp_rec2;
  comm_tab(5) := 20000 * 0.15;
END;
/

Assigning Values to Variables with the SELECT INTO Statement

A simple form of the SELECT INTO statement is:

SELECT select_item [, select_item ]... 
INTO variable_name [, variable_name ]...
FROM table_name;

For each select_item, there must be a corresponding, type-compatible variable_name. Because SQL does not have a BOOLEAN type, variable_name cannot be a BOOLEAN variable. For the complete syntax of the SELECT INTO statement, see "SELECT INTO Statement".

Example 2-26 uses a SELECT INTO statement to assign to the variable bonus the value that is 10% of the salary of the employee whose employee_id is 100.

Example 2-26 SELECT INTO Assigns Values to Variables

DECLARE
  bonus   NUMBER(8,2);
BEGIN
  SELECT salary * 0.10 INTO bonus
  FROM employees
  WHERE employee_id = 100;
END;

DBMS_OUTPUT.PUT_LINE('bonus = ' || TO_CHAR(bonus));
/

Result:

bonus = 2458.2

Assigning Values to Variables as Parameters of a Subprogram

If you pass a variable to a subprogram as an OUT or IN OUT parameter, and the subprogram assigns a value to the parameter, the variable retains that value after the subprogram finishes running. For more information, see "OUT Mode" and "IN OUT Mode".

Example 2-27 passes the variable new_sal to the procedure adjust_salary. The procedure assigns a value to the corresponding formal parameter, sal. Because sal is an IN OUT parameter, the variable new_sal retains the assigned value after the procedure finishes running.

Example 2-27 Assigning Values to Variables as Parameters of a Subprogram

DECLARE
  new_sal  NUMBER(8,2);
  emp_id   NUMBER(6) := 126;
  
  PROCEDURE adjust_salary (
    emp_id      NUMBER,
    sal IN OUT NUMBER
  )
  IS
    emp_job  VARCHAR2(10);
    avg_sal  NUMBER(8,2);
  BEGIN
    SELECT job_id INTO emp_job
    FROM employees
    WHERE employee_id = emp_id;
  
    SELECT AVG(salary) INTO avg_sal
    FROM employees
    WHERE job_id = emp_job;
  
    DBMS_OUTPUT.PUT_LINE ('The average salary for '
                          || emp_job
                          || ' employees: '
                          || TO_CHAR(avg_sal)
    );
 
    sal := (sal + avg_sal)/2;
  END;
 
BEGIN
  -- Assign initial value to new_sal:
 
  SELECT AVG(salary)
  INTO new_sal
  FROM employees;
 
  DBMS_OUTPUT.PUT_LINE ('initial value of new_sal: ' ||
                        TO_CHAR(new_sal)
                       );
 
  -- Pass new_sal to procedure:
 
  adjust_salary(emp_id, new_sal);
 
  DBMS_OUTPUT.PUT_LINE ('final value of new_sal: ' ||
                        TO_CHAR(new_sal)
                       );
END;
/
 

Result:

initial value of new_sal: 6461.83
The average salary for ST_CLERK employees: 3281.01
final value of new_sal: 5056.07

Assigning Values to BOOLEAN Variables

The only values that you can assign to a BOOLEAN variable are TRUE, FALSE, and NULL.

Example 2-28 initializes the BOOLEAN variable done to NULL by default, assigns it the literal value FALSE, compares it to the literal value TRUE, and assigns it the value of a BOOLEAN expression.

Example 2-28 Assigning BOOLEAN Values

DECLARE
  done    BOOLEAN;              -- Initial value is NULL by default
  counter NUMBER := 0;
BEGIN
  done := FALSE;                -- Assign literal value
  WHILE done != TRUE            -- Compare to literal value
    LOOP
      counter := counter + 1;
      done := (counter > 500);  -- Assign value of BOOLEAN expression
    END LOOP;
END;
/

For more information about the BOOLEAN data type, see "Predefined PL/SQL BOOLEAN Data Type".

Expressions

An expression always returns a single value. The simplest expressions, in order of increasing complexity, are:

  1. A single constant or variable (for example, a)

  2. A unary operator and its single operand (for example, -a)

  3. A binary operator and its two operands (for example, a+b)

An operand can be a variable, constant, literal, operator, function call, or placeholder—or another expression. Therefore, expressions can be arbitrarily complex. For expression syntax, see "Expression".

The data types of the operands determine the data type of the expression. Every time the expression is evaluated, a single value of that data type results.

Topics:

Concatenation Operator

The concatenation operator (||) appends one string operand to another, as Example 2-29 shows.

Example 2-29 Concatenation Operator

DECLARE
  x VARCHAR2(4) := 'suit';
  y VARCHAR2(4) := 'case';
BEGIN
  DBMS_OUTPUT.PUT_LINE (x || y);
END;
/
 

Result:

suitcase

The concatenation operator ignores null operands, as Example 2-30 shows.

Example 2-30 Concatenation Operator with NULL Operands

BEGIN
  DBMS_OUTPUT.PUT_LINE ('apple' || NULL || NULL || 'sauce');
END;
/
 

Result:

applesauce

For more information about the syntax of the concatenation operator, see character_expression ::=.

Operator Precedence

An operation is either a unary operator and its single operand or a binary operator and its two operands. The operations in an expression are evaluated in order of operator precedence.

Table 2-4 shows operator precedence from highest to lowest. Operators with equal precedence are evaluated in no particular order.

Table 2-4 Operator Precedence

Operator Operation

**

exponentiation

+, -

identity, negation

*, /

multiplication, division

+, -, ||

addition, subtraction, concatenation

=, <, >, <=, >=, <>, !=, ~=, ^=, IS NULL, LIKE, BETWEEN, IN

comparison

NOT

negation

AND

conjunction

OR

inclusion


To control the order of evaluation, enclose operations in parentheses, as in Example 2-31.

Example 2-31 Controlling Evaluation Order with Parentheses

DECLARE
  a INTEGER := 1+2**2;
  b INTEGER := (1+2)**2;
BEGIN
  DBMS_OUTPUT.PUT_LINE('a = ' || TO_CHAR(a));
  DBMS_OUTPUT.PUT_LINE('b = ' || TO_CHAR(b));
END;
/

Result:

a = 5
b = 9

When parentheses are nested, the most deeply nested operations are evaluated first.

In Example 2-32, the operations (1+2) and (3+4) are evaluated first, producing the values 3 and 7, respectively. Next, the operation 3*7 is evaluated, producing the result 21. Finally, the operation 21/7 is evaluated, producing the final value 3.

Example 2-32 Expression with Nested Parentheses

DECLARE
  a INTEGER := ((1+2)*(3+4))/7;
BEGIN
  DBMS_OUTPUT.PUT_LINE('a = ' || TO_CHAR(a));
END;
/

Result:

a = 3

You can also use parentheses to improve readability, as in Example 2-33, where the parentheses do not affect evaluation order.

Example 2-33 Improving Readability with Parentheses

DECLARE
  a INTEGER := 2**2*3**2;
  b INTEGER := (2**2)*(3**2);
BEGIN
  DBMS_OUTPUT.PUT_LINE('a = ' || TO_CHAR(a));
  DBMS_OUTPUT.PUT_LINE('b = ' || TO_CHAR(b));
END;
/

Result:

a = 36
b = 36

Example 2-34 shows the effect of operator precedence and parentheses in several more complex expressions.

Example 2-34 Operator Precedence

DECLARE
  salary      NUMBER := 60000;
  commission  NUMBER := 0.10;
BEGIN
  -- Division has higher precedence than addition:
  
  DBMS_OUTPUT.PUT_LINE('5 + 12 / 4 = ' || TO_CHAR(5 + 12 / 4));
  DBMS_OUTPUT.PUT_LINE('12 / 4 + 5 = ' || TO_CHAR(12 / 4 + 5));
  
 -- Parentheses override default operator precedence:
 
  DBMS_OUTPUT.PUT_LINE('8 + 6 / 2 = ' || TO_CHAR(8 + 6 / 2));
  DBMS_OUTPUT.PUT_LINE('(8 + 6) / 2 = ' || TO_CHAR((8 + 6) / 2));
 
  -- Most deeply nested operation is evaluated first:
 
  DBMS_OUTPUT.PUT_LINE('100 + (20 / 5 + (7 - 3)) = '
                      || TO_CHAR(100 + (20 / 5 + (7 - 3))));
 
  -- Parentheses, even when unnecessary, improve readability:
 
  DBMS_OUTPUT.PUT_LINE('(salary * 0.05) + (commission * 0.25) = '
    || TO_CHAR((salary * 0.05) + (commission * 0.25))
  );
 
  DBMS_OUTPUT.PUT_LINE('salary * 0.05 + commission * 0.25 = '
    || TO_CHAR(salary * 0.05 + commission * 0.25)
  );
END;
/
 

Result:

5 + 12 / 4 = 8
12 / 4 + 5 = 8
8 + 6 / 2 = 11
(8 + 6) / 2 = 7
100 + (20 / 5 + (7 - 3)) = 108
(salary * 0.05) + (commission * 0.25) = 3000.025
salary * 0.05 + commission * 0.25 = 3000.025

Logical Operators

The logical operators AND, OR, and NOT follow the tri-state logic shown in Table 2-5. AND and OR are binary operators; NOT is a unary operator.

Table 2-5 Logical Truth Table

x y x AND y x OR y NOT x

TRUE

TRUE

TRUE

TRUE

FALSE

TRUE

FALSE

FALSE

TRUE

FALSE

TRUE

NULL

NULL

TRUE

FALSE

FALSE

TRUE

FALSE

TRUE

TRUE

FALSE

FALSE

FALSE

FALSE

TRUE

FALSE

NULL

FALSE

NULL

TRUE

NULL

TRUE

NULL

TRUE

NULL

NULL

FALSE

FALSE

NULL

NULL

NULL

NULL

NULL

NULL

NULL


As Table 2-5 and Example 2-35 show, AND returns TRUE if and only if both operands are TRUE. (Several examples invoke the print_boolean procedure that Example 2-35 creates. The procedure uses the "IS [NOT] NULL Operator".)

Example 2-35 AND Operator

CREATE OR REPLACE PROCEDURE print_boolean (
  name   VARCHAR2,
  value  BOOLEAN
) IS
BEGIN
  IF value IS NULL THEN
    DBMS_OUTPUT.PUT_LINE (name || ' = NULL');
  ELSIF value = TRUE THEN
    DBMS_OUTPUT.PUT_LINE (name || ' = TRUE');
  ELSE
    DBMS_OUTPUT.PUT_LINE (name || ' = FALSE');
  END IF;
END;
/
 
DECLARE
  PROCEDURE print_x_and_y (
    x  BOOLEAN,
    y  BOOLEAN
  ) IS
  BEGIN
   print_boolean ('x', x);
   print_boolean ('y', y);
   print_boolean ('x AND y', x AND y);
 END print_x_and_y;
 
BEGIN
 print_x_and_y (FALSE, FALSE);
 print_x_and_y (TRUE, FALSE);
 print_x_and_y (FALSE, TRUE);
 print_x_and_y (TRUE, TRUE);
 
 print_x_and_y (TRUE, NULL);
 print_x_and_y (FALSE, NULL);
 print_x_and_y (NULL, TRUE);
 print_x_and_y (NULL, FALSE);
END;
/
 

Result:

x = FALSE
y = FALSE
x AND y = FALSE
x = TRUE
y = FALSE
x AND y = FALSE
x = FALSE
y = TRUE
x AND y = FALSE
x = TRUE
y = TRUE
x AND y = TRUE
x = TRUE
y = NULL
x AND y = NULL
x = FALSE
y = NULL
x AND y = FALSE
x = NULL
y = TRUE
x AND y = NULL
x = NULL
y = FALSE
x AND y = FALSE

As Table 2-5 and Example 2-36 show, OR returns TRUE if either operand is TRUE. (Example 2-36 invokes the print_boolean procedure from Example 2-35.)

Example 2-36 OR Operator

DECLARE
  PROCEDURE print_x_or_y (
    x  BOOLEAN,
    y  BOOLEAN
  ) IS
  BEGIN
    print_boolean ('x', x);
    print_boolean ('y', y);
    print_boolean ('x OR y', x OR y);
  END print_x_or_y;
 
BEGIN
  print_x_or_y (FALSE, FALSE);
  print_x_or_y (TRUE, FALSE);
  print_x_or_y (FALSE, TRUE);
  print_x_or_y (TRUE, TRUE);
 
  print_x_or_y (TRUE, NULL);
  print_x_or_y (FALSE, NULL);
  print_x_or_y (NULL, TRUE);
  print_x_or_y (NULL, FALSE);
END;
/
 

Result:

x = FALSE
y = FALSE
x OR y = FALSE
x = TRUE
y = FALSE
x OR y = TRUE
x = FALSE
y = TRUE
x OR y = TRUE
x = TRUE
y = TRUE
x OR y = TRUE
x = TRUE
y = NULL
x OR y = TRUE
x = FALSE
y = NULL
x OR y = NULL
x = NULL
y = TRUE
x OR y = TRUE
x = NULL
y = FALSE
x OR y = NULL

As Table 2-5 and Example 2-37 show, NOT returns the opposite of its operand, unless the operand is NULL. NOT NULL returns NULL, because NULL is an indeterminate value. (Example 2-37 invokes the print_boolean procedure from Example 2-35.)

Example 2-37 NOT Operator

DECLARE
  PROCEDURE print_not_x (
    x  BOOLEAN
  ) IS
  BEGIN
    print_boolean ('x', x);
    print_boolean ('NOT x', NOT x);
  END print_not_x;
 
BEGIN
  print_not_x (TRUE);
  print_not_x (FALSE);
  print_not_x (NULL);
END;
/
 

Result:

x = TRUE
NOT x = FALSE
x = FALSE
NOT x = TRUE
x = NULL
NOT x = NULL

In Example 2-38, you might expect the sequence of statements to run because x and y seem unequal. But, NULL values are indeterminate. Whether x equals y is unknown. Therefore, the IF condition yields NULL and the sequence of statements is bypassed.

Example 2-38 NULL Value in Unequal Comparison

DECLARE
  x NUMBER := 5;
  y NUMBER := NULL;
BEGIN
  IF x != y THEN  -- yields NULL, not TRUE
    DBMS_OUTPUT.PUT_LINE('x != y');  -- not run
  ELSIF x = y THEN -- also yields NULL
    DBMS_OUTPUT.PUT_LINE('x = y');
  ELSE
    DBMS_OUTPUT.PUT_LINE
      ('Can''t tell if x and y are equal or not.');
  END IF;
END;
/
 

Result:

Can't tell if x and y are equal or not.

In Example 2-39, you might expect the sequence of statements to run because a and b seem equal. But, again, that is unknown, so the IF condition yields NULL and the sequence of statements is bypassed.

Example 2-39 NULL Value in Equal Comparison

DECLARE
  a NUMBER := NULL;
  b NUMBER := NULL;
BEGIN
  IF a = b THEN  -- yields NULL, not TRUE
    DBMS_OUTPUT.PUT_LINE('a = b');  -- not run
  ELSIF a != b THEN  -- yields NULL, not TRUE
    DBMS_OUTPUT.PUT_LINE('a != b');  -- not run
  ELSE
    DBMS_OUTPUT.PUT_LINE('Can''t tell if two NULLs are equal');
  END IF;
END;
/
 

Result:

Can't tell if two NULLs are equal

In Example 2-40, the two IF statements appear to be equivalent. However, if either x or y is NULL, then the first IF statement assigns the value of y to high and the second IF statement assigns the value of x to high.

Example 2-40 NOT NULL Equals NULL

DECLARE
  x    INTEGER := 2;
  Y    INTEGER := 5;
  high INTEGER;
BEGIN
  IF (x > y)       -- If x or y is NULL, then (x > y) is NULL
    THEN high := x;  -- run if (x > y) is TRUE
    ELSE high := y;  -- run if (x > y) is FALSE or NULL
  END IF;
  
  IF NOT (x > y)   -- If x or y is NULL, then NOT (x > y) is NULL
    THEN high := y;  -- run if NOT (x > y) is TRUE
    ELSE high := x;  -- run if NOT (x > y) is FALSE or NULL
  END IF;
END;
/

Example 2-41 invokes the print_boolean procedure from Example 2-35 three times. The third and first invocation are logically equivalent—the parentheses in the third invocation only improve readability. The parentheses in the second invocation change the order of operation.

Example 2-41 Changing Evaluation Order of Logical Operators

DECLARE
  x  BOOLEAN := FALSE;
  y  BOOLEAN := FALSE;
  
BEGIN
  print_boolean ('NOT x AND y', NOT x AND y);
  print_boolean ('NOT (x AND y)', NOT (x AND y));
  print_boolean ('(NOT x) AND y', (NOT x) AND y);
END;
/
 

Result:

NOT x AND y = FALSE
NOT (x AND y) = TRUE
(NOT x) AND y = FALSE

Short-Circuit Evaluation

When evaluating a logical expression, PL/SQL uses short-circuit evaluation. That is, PL/SQL stops evaluating the expression as soon as it can determine the result. Therefore, you can write expressions that might otherwise cause errors.

In Example 2-42, short-circuit evaluation prevents the OR expression from causing a divide-by-zero error. When the value of on_hand is zero, the value of the left operand is TRUE, so PL/SQL does not evaluate the right operand. If PL/SQL evaluated both operands before applying the OR operator, the right operand would cause a division by zero error.

Example 2-42 Short-Circuit Evaluation

DECLARE
  on_hand  INTEGER := 0;
  on_order INTEGER := 100;
BEGIN
  -- Does not cause divide-by-zero error;
  -- evaluation stops after first expression
  
  IF (on_hand = 0) OR ((on_order / on_hand) < 5) THEN
    DBMS_OUTPUT.PUT_LINE('On hand quantity is zero.');
  END IF;
END;
/
 

Result:

On hand quantity is zero.

Comparison Operators

Comparison operators compare one expression to another. The result is always either TRUE, FALSE, or NULL. If the value of one expression is NULL, then the result of the comparison is also NULL.

The comparison operators are:

Note:

Using CLOB values with comparison operators can create temporary LOB values. Ensure that your temporary tablespace is large enough to handle them.

Relational Operators

Example 2-42 summarizes the relational operators.

Table 2-6 Relational Operators

Operator Meaning

=

equal to

<>, !=, ~=, ^=

not equal to

<

less than

>

greater than

<=

less than or equal to

>=

greater than or equal to


Topics:

Arithmetic Comparisons

One number is greater than another if it represents a larger quantity. Real numbers are stored as approximate values, so Oracle recommends comparing them for equality or inequality.

Example 2-43 invokes the print_boolean procedure from Example 2-35 to print the values of expressions that use relational operators to compare arithmetic values.

Example 2-43 Relational Operators in Expressions

BEGIN
  print_boolean ('(2 + 2 =  4)', 2 + 2 = 4);
  
  print_boolean ('(2 + 2 <> 4)', 2 + 2 <> 4);
  print_boolean ('(2 + 2 != 4)', 2 + 2 != 4);
  print_boolean ('(2 + 2 ~= 4)', 2 + 2 ~= 4);
  print_boolean ('(2 + 2 ^= 4)', 2 + 2 ^= 4);
  
  print_boolean ('(1 < 2)', 1 < 2);
 
  print_boolean ('(1 > 2)', 1 > 2);
 
  print_boolean ('(1 <= 2)', 1 <= 2);
 
  print_boolean ('(1 >= 1)', 1 >= 1);
END;
/
 

Result:

(2 + 2 =  4) = TRUE
(2 + 2 <> 4) = FALSE
(2 + 2 != 4) = FALSE
(2 + 2 ~= 4) = FALSE
(2 + 2 ^= 4) = FALSE
(1 < 2) = TRUE
(1 > 2) = FALSE
(1 <= 2) = TRUE
(1 >= 1) = TRUE
BOOLEAN Comparisons

By definition, TRUE is greater than FALSE. Any comparison with NULL returns NULL.

Character Comparisons

By default, one character is greater than another if its binary value is larger. For example, this expression is true:

'y' > 'r'

Strings are compared character by character. For example, this expression is true:

'Kathy' > 'Kathryn'

If you set the initialization parameter NLS_COMP=ANSI, string comparisons use the collating sequence identified by the NLS_SORT initialization parameter.

A collating sequence is an internal ordering of the character set in which a range of numeric codes represents the individual characters. One character value is greater than another if its internal numeric value is larger. Each language might have different rules about where such characters occur in the collating sequence. For example, an accented letter might be sorted differently depending on the database character set, even though the binary value is the same in each case.

By changing the value of the NLS_SORT parameter, you can perform comparisons that are case-insensitive and accent-insensitive.

A case-insensitive comparison treats corresponding uppercase and lowercase letters as the same letter. For example, these expressions are true:

'a' = 'A'
'Alpha' = 'ALPHA'

To make comparisons case-insensitive, append _CI to the value of the NLS_SORT parameter (for example, BINARY_CI or XGERMAN_CI).

An accent-insensitive comparison is case-insensitive, and also treats letters that differ only in accents or punctuation characters as the same letter. For example, these expressions are true:

'Cooperate' = 'Co-Operate'
'Co-Operate' = 'coöperate'

To make comparisons both case-insensitive and accent-insensitive, append _AI to the value of the NLS_SORT parameter (for example, BINARY_AI or FRENCH_M_AI).

Semantic differences between the CHAR and VARCHAR2 data types affect character comparisons. For more information, see "Comparing Character Values".

Date Comparisons

One date is greater than another if it is more recent. For example, this expression is true:

'01-JAN-91' > '31-DEC-90'

IS [NOT] NULL Operator

The IS NULL operator returns the BOOLEAN value TRUE if its operand is NULL or FALSE if it is not NULL. The IS NOT NULL operator does the opposite. Comparisons involving NULL values always yield NULL.

To test whether a value is NULL, use IF value IS NULL, as in these examples:

LIKE Operator

The LIKE operator compares a character, string, or CLOB value to a pattern and returns TRUE if the value matches the pattern and FALSE if it does not.

The pattern can include the two wildcard characters underscore (_) and percent sign (%). Underscore matches exactly one character. Percent sign (%) matches zero or more characters.

Case is significant. The string 'Johnson' matches the pattern 'J%s_n' but not 'J%S_N', as Example 2-44 shows.

Example 2-44 LIKE Operator in Expression

DECLARE
  PROCEDURE compare (
    value   VARCHAR2,
    pattern VARCHAR2
  ) IS
  BEGIN
    IF value LIKE pattern THEN
      DBMS_OUTPUT.PUT_LINE ('TRUE');
    ELSE
      DBMS_OUTPUT.PUT_LINE ('FALSE');
    END IF;
  END;
BEGIN
  compare('Johnson', 'J%s_n');
  compare('Johnson', 'J%S_N');
END;
/
 

Result:

TRUE
FALSE

To search for the percent sign or underscore, define an escape character and put it before the percent sign or underscore.

Example 2-45 uses the backslash as the escape character, so that the percent sign in the string does not act as a wildcard.

Example 2-45 Escape Character in Pattern

DECLARE
  PROCEDURE half_off (sale_sign VARCHAR2) IS
  BEGIN
    IF sale_sign LIKE '50\% off!' ESCAPE '\' THEN
      DBMS_OUTPUT.PUT_LINE ('TRUE');
    ELSE
      DBMS_OUTPUT.PUT_LINE ('FALSE');
    END IF;
  END;
BEGIN
  half_off('Going out of business!');
  half_off('50% off!');
END;
/
 

Result:

FALSE
TRUE

BETWEEN Operator

The BETWEEN operator tests whether a value lies in a specified range. x BETWEEN a AND b returns the same value as (x>=a) AND (x<=b).

Example 2-46 invokes the print_boolean procedure from Example 2-35 to print the values of expressions that include the BETWEEN operator.

Example 2-46 BETWEEN Operator in Expressions

BEGIN
  print_boolean ('2 BETWEEN 1 AND 3', 2 BETWEEN 1 AND 3);
  print_boolean ('2 BETWEEN 2 AND 3', 2 BETWEEN 2 AND 3);
  print_boolean ('2 BETWEEN 1 AND 2', 2 BETWEEN 1 AND 2);
  print_boolean ('2 BETWEEN 3 AND 4', 2 BETWEEN 3 AND 4);
END;
/
 

Result:

2 BETWEEN 1 AND 3 = TRUE
2 BETWEEN 2 AND 3 = TRUE
2 BETWEEN 1 AND 2 = TRUE
2 BETWEEN 3 AND 4 = FALSE

IN Operator

The IN operator tests set membership. x IN (set) returns TRUE only if x equals a member of set.

Example 2-47 invokes the print_boolean procedure from Example 2-35 to print the values of expressions that include the IN operator.

Example 2-47 IN Operator in Expressions

DECLARE
  letter VARCHAR2(1) := 'm';
BEGIN
  print_boolean (
    'letter IN (''a'', ''b'', ''c'')',
    letter IN ('a', 'b', 'c')
  );
  print_boolean (
    'letter IN (''z'', ''m'', ''y'', ''p'')',
    letter IN ('z', 'm', 'y', 'p')
  );
END;
/
 

Result:

letter IN ('a', 'b', 'c') = FALSE
letter IN ('z', 'm', 'y', 'p') = TRUE
 

Example 2-48 shows what happens when set includes a NULL value. (Example 2-48 invokes the print_boolean procedure from Example 2-35.)

Example 2-48 IN Operator with Sets with NULL Values

DECLARE
  a INTEGER; -- Initialized to NULL by default
  b INTEGER := 10;
  c INTEGER := 100;
BEGIN
  print_boolean ('100 IN (a, b, c)', 100 IN (a, b, c));
  print_boolean ('100 NOT IN (a, b, c)', 100 NOT IN (a, b, c));
  
  print_boolean ('100 IN (a, b)', 100 IN (a, b));
  print_boolean ('100 NOT IN (a, b)', 100 NOT IN (a, b));
 
  print_boolean ('a IN (a, b)', a IN (a, b));
  print_boolean ('a NOT IN (a, b)', a NOT IN (a, b));
END;
/
 

Result:

100 IN (a, b, c) = TRUE
100 NOT IN (a, b, c) = FALSE
100 IN (a, b) = NULL
100 NOT IN (a, b) = NULL
a IN (a, b) = NULL
a NOT IN (a, b) = NULL

BOOLEAN Expressions

A BOOLEAN expression is an expression that returns a BOOLEAN value—TRUE, FALSE, or NULL. The simplest BOOLEAN expression is a single BOOLEAN value, constant, or variable. The following are also BOOLEAN expressions:

NOT boolean_expression
boolean_expression relational_operator boolean_expression
boolean_expression { AND | OR } boolean_expression

For a list of relational operators, see Table 2-6. For the complete syntax of a BOOLEAN expression, see boolean_expression ::=.

Typically, you use BOOLEAN expressions as conditions in control statements (which are described in Chapter 4, "PL/SQL Control Statements") and in WHERE clauses of DML statements.

You can use a BOOLEAN variable itself as a condition; you need not compare it to the value TRUE or FALSE. In Example 2-49, the conditions in the loops are equivalent.

Example 2-49 Equivalent BOOLEAN Expressions as Conditions in Loops

DECLARE
  done BOOLEAN;
BEGIN
  -- These WHILE loops are equivalent
  
  done := FALSE;
  WHILE done = FALSE
    LOOP
      done := TRUE;
    END LOOP;
 
  done := FALSE;
  WHILE NOT (done = TRUE)
    LOOP
      done := TRUE;
    END LOOP;
 
  done := FALSE;
  WHILE NOT done
    LOOP
      done := TRUE;
    END LOOP;
END;
/

CASE Expressions

Topics:

Simple CASE Expression

For this explanation, assume that a simple CASE expression has this syntax:

CASE selector
WHEN selector_value_1 THEN result_1
WHEN selector_value_2 THEN result_2
...
WHEN selector_value_n THEN result_n
[ ELSE
  else_result ]
END]

The selector is an expression (typically a single variable). Each selector_value and each result can be either a literal or an expression.

The simple CASE expression returns the first result for which selector_value matches selector. Remaining expressions are not evaluated. If no selector_value matches selector, the CASE expression returns else_result if it exists and NULL otherwise.

See Also:

simple_case_expression ::= for the complete syntax

Example 2-50 assigns the value of a simple CASE expression to the variable appraisal. The selector is grade.

Example 2-50 Simple CASE Expression

DECLARE
  grade CHAR(1) := 'B';
  appraisal VARCHAR2(20);
BEGIN
  appraisal :=
    CASE grade
      WHEN 'A' THEN 'Excellent'
      WHEN 'B' THEN 'Very Good'
      WHEN 'C' THEN 'Good'
      WHEN 'D' THEN 'Fair'
      WHEN 'F' THEN 'Poor'
      ELSE 'No such grade'
    END;
    DBMS_OUTPUT.PUT_LINE ('Grade ' || grade || ' is ' || appraisal);
END;
/
 

Result:

Grade B is Very Good

If selector has the value NULL, it cannot be matched by WHEN NULL, as Example 2-51 shows. Instead, use a searched CASE expression with WHEN boolean_expression IS NULL, as in Example 2-53.

Example 2-51 Simple CASE Expression with WHEN NULL

DECLARE
  grade CHAR(1); -- NULL by default
  appraisal VARCHAR2(20);
BEGIN
  appraisal :=
  CASE grade
    WHEN NULL THEN 'No grade assigned'
    WHEN 'A' THEN 'Excellent'
    WHEN 'B' THEN 'Very Good'
    WHEN 'C' THEN 'Good'
    WHEN 'D' THEN 'Fair'
    WHEN 'F' THEN 'Poor'
    ELSE 'No such grade'
  END;
  DBMS_OUTPUT.PUT_LINE ('Grade ' || grade || ' is ' || appraisal);
END;
/

Result:

Grade  is No such grade

Searched CASE Expression

For this explanation, assume that a searched CASE expression has this syntax:

CASE
WHEN boolean_expression_1 THEN result_1
WHEN boolean_expression_2 THEN result_2
...
WHEN boolean_expression_n THEN result_n
[ ELSE
  else_result ]
END]

The searched CASE expression returns the first result for which boolean_expression is TRUE. Remaining expressions are not evaluated. If no boolean_expression is TRUE, the CASE expression returns else_result if it exists and NULL otherwise.

See Also:

searched_case_expression ::= for the complete syntax

Example 2-52 assigns the value of a searched CASE expression to the variable appraisal.

Example 2-52 Searched CASE Expression

DECLARE
  grade      CHAR(1) := 'B';
  appraisal  VARCHAR2(120);
  id         NUMBER  := 8429862;
  attendance NUMBER := 150;
  min_days   CONSTANT NUMBER := 200;
  
  FUNCTION attends_this_school (id NUMBER)
    RETURN BOOLEAN IS
  BEGIN
    RETURN TRUE;
  END;
BEGIN
  appraisal :=
  CASE
    WHEN attends_this_school(id) = FALSE
      THEN 'Student not enrolled'
    WHEN grade = 'F' OR attendance < min_days
      THEN 'Poor (poor performance or bad attendance)'
    WHEN grade = 'A' THEN 'Excellent'
    WHEN grade = 'B' THEN 'Very Good'
    WHEN grade = 'C' THEN 'Good'
    WHEN grade = 'D' THEN 'Fair'
    ELSE 'No such grade'
  END;
  DBMS_OUTPUT.PUT_LINE
    ('Result for student ' || id || ' is ' || appraisal);
END;
/
 

Result:

Result for student 8429862 is Poor (poor performance or bad attendance)

Example 2-53 uses a searched CASE expression to solve the problem in Example 2-51.

Example 2-53 Searched CASE Expression with WHEN condition IS NULL

DECLARE
  grade CHAR(1); -- NULL by default
  appraisal VARCHAR2(20);
BEGIN
  appraisal :=
    CASE
      WHEN grade IS NULL THEN 'No grade assigned'
      WHEN grade = 'A' THEN 'Excellent'
      WHEN grade = 'B' THEN 'Very Good'
      WHEN grade = 'C' THEN 'Good'
      WHEN grade = 'D' THEN 'Fair'
      WHEN grade = 'F' THEN 'Poor'
      ELSE 'No such grade'
    END;
    DBMS_OUTPUT.PUT_LINE ('Grade ' || grade || ' is ' || appraisal);
END;
/
 

Result:

Grade  is No grade assigned

SQL Functions in PL/SQL Expressions

In PL/SQL expressions, you can use all SQL functions except:

  • Aggregate functions (such as AVG and COUNT)

  • Analytic functions (such as LAG and RATIO_TO_REPORT)

  • Collection functions (such as CARDINALITY and SET)

  • Data mining functions (such as CLUSTER_ID and FEATURE_VALUE)

  • Encoding and decoding functions (such as DECODE and DUMP)

  • Model functions (such as ITERATION_NUMBER and PREVIOUS)

  • Object reference functions (such as REF and VALUE)

  • XML functions (such as APPENDCHILDXML and EXISTSNODE)

  • These conversion functions:

    • BIN_TO_NUM

    • CAST

    • RAWTONHEX

    • ROWIDTONCHAR

  • These miscellaneous functions:

    • CUBE_TABLE

    • DATAOBJ_TO_PARTITION

    • LNNVL

    • SYS_CONNECT_BY_PATH

    • SYS_TYPEID

    • WIDTH_BUCKET

PL/SQL supports an overload of BITAND for which the arguments and result are BINARY_INTEGER.

When used in a PL/SQL expression, the RAWTOHEX function accepts an argument of data type RAW and returns a VARCHAR2 value with the hexadecimal representation of bytes that comprise the value of the argument. Arguments of types other than RAW can be specified only if they can be implicitly converted to RAW. This conversion is possible for CHAR, VARCHAR2, and LONG values that are valid arguments of the HEXTORAW function, and for LONG RAW and BLOB values of up to 16380 bytes.

Error-Reporting Functions

PL/SQL has two built-in error-reporting functions, SQLCODE and SQLERRM, for use in PL/SQL exception-handling code. For their descriptions, see "SQLCODE Function" and "SQLERRM Function".

You cannot use the SQLCODE and SQLERRM functions in SQL statements.

Pragmas

A pragma is an instruction to the compiler. It is processed at compile time, not at run time. The basic syntax is:

PRAGMA instruction

For the complete syntax, see pragma ::=.

Conditional Compilation

Conditional compilation lets you customize the functionality of a PL/SQL application without removing source code. For example, you can:

Topics:

How Conditional Compilation Works

Note:

The conditional compilation feature and related PL/SQL packages are available for Oracle Database release 10.1.0.4 and later releases.

Conditional compilation uses selection directives, which are similar to IF statements, to select source text for compilation. The condition in a selection directive usually includes an inquiry directive. Error directives raise user-defined errors. All conditional compilation directives are built from preprocessor control tokens and PL/SQL text.

Topics:

Preprocessor Control Tokens

A preprocessor control token identifies code that is processed before the PL/SQL unit is compiled.

Syntax

$plsql_identifier

There cannot be space between $ and plsql_identifier. For information about plsql_identifier, see "Identifiers". The character $ can also appear inside plsql_identifier, but it has no special meaning there.

These preprocessor control tokens are reserved:

  • $IF

  • $THEN

  • $ELSE

  • $ELSIF

  • $ERROR

Selection Directives

A selection directive selects source text to compile.

Syntax

$IF boolean_static_expression $THEN
   text
[ $ELSIF boolean_static_expression $THEN
   text
]...
[ $ELSE
   text
$END
]

For the syntax of boolean_static_expression, see "BOOLEAN Static Expressions". The text can be anything, but typically, it is either a statement (described in "statement ::=") or an error directive (described in "Error Directives").

The selection directive evaluates the BOOLEAN static expressions in the order that they appear until either one expression has the value TRUE or the list of expressions is exhausted. If one expression has the value TRUE, its text is selected for compilation, the remaining expressions are not evaluated, and their text is not analyzed. If no expression has the value TRUE, then if $ELSE is present, its text is selected for compilation; otherwise, no text is selected for compilation.

For examples of selection directives, see "Conditional Compilation Examples".

See Also:

"Conditional Selection Statements" for information about the IF statement, which has the same logic as the selection directive

Error Directives

An error directive produces a user-defined error message during compilation.

Syntax

$ERROR varchar2_static_expression $END

It produces this compile-time error message, where string is the value of varchar2_static_expression:

PLS-00179: $ERROR: string

For the syntax of varchar2_static_expression, see "VARCHAR2 Static Expressions".

For an example of an error directive, see Example 2-58.

Inquiry Directives

An inquiry directive provides information about the compilation environment.

Syntax

$$name

For information about name, which is an unquoted PL/SQL identifier, see "Identifiers".

An inquiry directive typically appears in the boolean_static_expression of a selection directive, but it can appear anywhere that a variable or literal of its type can appear. Moreover, it can appear where regular PL/SQL allows only a literal (not a variable)— for example, to specify the size of a VARCHAR2 variable.

Topics:

Predefined Inquiry Directives

The predefined inquiry directives are:

  • $$PLSQL_LINE

    A PLS_INTEGER literal whose value is the number of the source line on which the directive appears in the current PL/SQL unit. An example of $$PLSQL_LINE in a selection directive is:

    $IF $$PLSQL_LINE = 32 $THEN ...
    
  • $$PLSQL_UNIT

    A VARCHAR2 literal that contains the name of the current PL/SQL unit. If the current PL/SQL unit is an anonymous block, $$PLSQL_UNIT contains a NULL value. An example of $$PLSQL_UNIT in a selection directive is:

    $IF $$PLSQL_UNIT IS NULL $THEN ...
    

    Because a selection directive needs a BOOLEAN static expression, you cannot use a VARCHAR2 comparison such as:

    $IF $$PLSQL_UNIT = 'AWARD_BONUS' $THEN ...
    
  • $$plsql_compilation_parameter

    The name plsql_compilation_parameter is a PL/SQL compilation parameter (for example, PLSCOPE_SETTINGS). For descriptions of these parameters, see Table 1-1.

Example 2-54, a SQL*Plus script, uses the predefined inquiry directives $$PLSQL_LINE and $$PLSQL_UNIT as ordinary PLS_INTEGER and VARCHAR2 literals, respectively, to show how their values are assigned.

Example 2-54 Predefined Inquiry Directives $$PLSQL_LINE and $$PLSQL_UNIT

SQL> CREATE OR REPLACE PROCEDURE p
  2  IS
  3    i PLS_INTEGER;
  4  BEGIN
  5    DBMS_OUTPUT.PUT_LINE('Inside p');
  6    i := $$PLSQL_LINE;
  7    DBMS_OUTPUT.PUT_LINE('i = ' || i);
  8    DBMS_OUTPUT.PUT_LINE('$$PLSQL_LINE = ' || $$PLSQL_LINE);
  9    DBMS_OUTPUT.PUT_LINE('$$PLSQL_UNIT = ' || $$PLSQL_UNIT);
 10  END;
 11  /
 
Procedure created.
 
SQL> BEGIN
  2   p;
  3   DBMS_OUTPUT.PUT_LINE('Outside p');
  4   DBMS_OUTPUT.PUT_LINE('$$PLSQL_UNIT = ' || $$PLSQL_UNIT);
  5  END;
  6  /
 

Result:

Inside p
i = 6
$$PLSQL_LINE = 8
$$PLSQL_UNIT = P
Outside p
$$PLSQL_UNIT =
 
PL/SQL procedure successfully completed.

Example 2-55 displays the current values of PL/SQL the compilation parameters.

Example 2-55 Displaying Values of PL/SQL Compilation Parameters

BEGIN
  DBMS_OUTPUT.PUT_LINE('$$PLSCOPE_SETTINGS = '     || $$PLSCOPE_SETTINGS);
  DBMS_OUTPUT.PUT_LINE('$$PLSQL_CCFLAGS = '        || $$PLSQL_CCFLAGS);
  DBMS_OUTPUT.PUT_LINE('$$PLSQL_CODE_TYPE = '      || $$PLSQL_CODE_TYPE);
  DBMS_OUTPUT.PUT_LINE('$$PLSQL_OPTIMIZE_LEVEL = ' || $$PLSQL_OPTIMIZE_LEVEL);
  DBMS_OUTPUT.PUT_LINE('$$PLSQL_WARNINGS = '       || $$PLSQL_WARNINGS);
  DBMS_OUTPUT.PUT_LINE('$$NLS_LENGTH_SEMANTICS = ' || $$NLS_LENGTH_SEMANTICS);
END;
/

Result:

$$PLSCOPE_SETTINGS =
$$PLSQL_CCFLAGS =
$$PLSQL_CODE_TYPE = INTERPRETED
$$PLSQL_OPTIMIZE_LEVEL = 2
$$PLSQL_WARNINGS = ENABLE:ALL
$$NLS_LENGTH_SEMANTICS = BYTE

Note:

In the SQL*Plus environment, you can display the current values of initialization parameters, including the PL/SQL compilation parameters, with the command SHOW PARAMETERS. For more information about the SHOW command and its PARAMETERS option, see SQL*Plus User's Guide and Reference.
Assigning Values to Inquiry Directives

You can assign values to inquiry directives with the PLSQL_CCFLAGS compilation parameter. For example:

ALTER SESSION SET PLSQL_CCFLAGS = 
  'name1:value1, name2:value2, ... namen:valuen'

Each value must be either a BOOLEAN literal (TRUE, FALSE, or NULL) a or PLS_INTEGER literal. The data type of value determines the data type of name.

The same name can appear multiple times, with values of the same or different data types. Later assignments override earlier assignments. For example, this command sets the value of $$flag to 5 and its data type to PLS_INTEGER:

ALTER SESSION SET PLSQL_CCFLAGS = 'flag:TRUE, flag:5'

Oracle recommends against using PLSQL_CCFLAGS to assign values to predefined inquiry directives, including compilation parameters. To assign values to compilation parameters, Oracle recommends using the ALTER SESSION statement. For more information about the ALTER SESSION statement, see Oracle Database SQL Language Reference.

Example 2-56 uses PLSQL_CCFLAGS to assign a value to the user-defined inquiry directive $$Some_Flag and (though not recommended) to itself. Because later assignments override earlier assignments, the resulting value of $$Some_Flag is 2 and the resulting value of PLSQL_CCFLAGS is the value that it assigns to itself (99), not the value that the ALTER SESSION statement assigns to it ('Some_Flag:1, Some_Flag:2, PLSQL_CCFlags:99').

Example 2-56 PLSQL_CCFLAGS Assigns Value to Itself

ALTER SESSION SET
PLSQL_CCFlags = 'Some_Flag:1, Some_Flag:2, PLSQL_CCFlags:99'
/
BEGIN
  Print($$Some_Flag);
  Print($$PLSQL_CCFlags);
END;
/

Result:

2
99

Note:

The compile-time value of PLSQL_CCFLAGS is stored with the metadata of stored PL/SQL units, which means that you can reuse the value when you explicitly recompile the units. For more information, see "PL/SQL Units and Compilation Parameters".

For more information about PLSQL_CCFLAGS, see Oracle Database Reference.

Unresolvable Inquiry Directives

If an inquiry directive ($$name) cannot be resolved (that is, if its value cannot be determined) and the source text is not wrapped, then warning PLW-6003 is generated and NULL is substituted for the value of the unresolved inquiry directive. If the source text is wrapped, the warning message is disabled, so that the unresolved inquiry directive is not revealed. For information about wrapping PL/SQL source text, see Appendix A, "PL/SQL Source Code Wrapping".

Static Expressions

A static expression is an expression whose value can be determined at compilation time (that is, it does not include references to variables or functions). Static expressions are the only expressions that can appear in conditional compilation directives.

Topics:

See Also:

"Expressions" for general information about expressions
PLS_INTEGER Static Expressions

PLS_INTEGER static expressions are:

  • PLS_INTEGER literals

    For information about numeric literals, see "Numeric Literals".

  • PLS_INTEGER static constants

    For information about static constants, see "Static Constants".

  • NULL

See Also:

"PLS_INTEGER and BINARY_INTEGER Data Types" for information about the PLS_INTEGER data type
BOOLEAN Static Expressions

BOOLEAN static expressions are:

  • BOOLEAN literals (TRUE, FALSE, or NULL)

  • BOOLEAN static constants

    For information about static constants, see "Static Constants".

  • Where x and y are PLS_INTEGER static expressions:

    • x > y

    • x < y

    • x >= y

    • x <= y

    • x = y

    • x <> y

    For information about PLS_INTEGER static expressions, see "PLS_INTEGER Static Expressions".

  • Where x and y are BOOLEAN expressions:

    • NOT y

    • x AND y

    • x OR y

    • x > y

    • x >= y

    • x = y

    • x <= y

    • x <> y

    For information about BOOLEAN expressions, see "BOOLEAN Expressions".

  • Where x is a static expression:

    • x IS NULL

    • x IS NOT NULL

    For information about static expressions, see "Static Expressions".

See Also:

"Predefined PL/SQL BOOLEAN Data Type" for information about the BOOLEAN data type
VARCHAR2 Static Expressions

VARCHAR2 static expressions are:

See Also:

"CHAR and VARCHAR2 Data Types" for information about the VARCHAR2 data type
Static Constants

A static constant is declared in a package specification with this syntax:

constant_name CONSTANT data_type := static_expression;

The type of static_expression must be the same as data_type (either BOOLEAN or PLS_INTEGER).

The static constant must always be referenced as package_name.constant_name, even in the body of the package_name package.

If you use constant_name in the BOOLEAN expression in a conditional compilation directive in a PL/SQL unit, then the PL/SQL unit depends on the package package_name. If you alter the package specification, the dependent PL/SQL unit might become invalid and need to be recompiled (for information about the invalidation of dependent objects, see Oracle Database Advanced Application Developer's Guide).

If you use a package with static constants to control conditional compilation in multiple PL/SQL units, Oracle recommends that you create only the package specification, and dedicate it exclusively to controlling conditional compilation. This practice minimizes invalidations caused by altering the package specification.

To control conditional compilation in a single PL/SQL unit, you can set flags in the PLSQL_CCFLAGS compilation parameter. For information about this parameter, see "Assigning Values to Inquiry Directives" and Oracle Database Reference.

In Example 2-57, the package my_debug defines the static constants debug and trace to control debugging and tracing in multiple PL/SQL units. The procedure my_proc1 uses only debug, and the procedure my_proc2 uses only trace, but both procedures depend on the package. However, the recompiled code might not be different. For example, if you only change the value of debug to FALSE and then recompile the two procedures, the compiled code for my_proc1 changes, but the compiled code for my_proc2 does not.

Example 2-57 Static Constants

CREATE PACKAGE my_debug IS
  debug CONSTANT BOOLEAN := TRUE;
  trace CONSTANT BOOLEAN := TRUE;
END my_debug;
/
 
CREATE PROCEDURE my_proc1 IS
BEGIN
  $IF my_debug.debug $THEN
    DBMS_OUTPUT.put_line('Debugging ON');
  $ELSE
    DBMS_OUTPUT.put_line('Debugging OFF');
  $END
END my_proc1;
/
 
CREATE PROCEDURE my_proc2 IS
BEGIN
  $IF my_debug.trace $THEN
    DBMS_OUTPUT.put_line('Tracing ON');
  $ELSE
    DBMS_OUTPUT.put_line('Tracing OFF');
  $END
END my_proc2;
/

See Also:

DBMS_DB_VERSION Package

The DBMS_DB_VERSION package provides these static constants:

  • The PLS_INTEGER constant VERSION identifies the current Oracle Database version.

  • The PLS_INTEGER constant RELEASE identifies the current Oracle Database release number.

  • Each BOOLEAN constant of the form VER_LE_v has the value TRUE if the database version is less than or equal to v; otherwise, it has the value FALSE.

  • Each BOOLEAN constant of the form VER_LE_v_r has the value TRUE if the database version is less than or equal to v and release is less than or equal to r; otherwise, it has the value FALSE.

  • All constants representing Oracle Database 10g release 1 or earlier have the value FALSE.

For more information about the DBMS_DB_VERSION package, see Oracle Database PL/SQL Packages and Types Reference.

Conditional Compilation Examples

Example 2-58 generates an error message if the database version and release is less than 10.2; otherwise, it displays a message saying that the version and release are supported and uses a COMMIT statement that became available at release 10.2.

Example 2-58 Code for Checking Database Version

BEGIN
  $IF DBMS_DB_VERSION.VER_LE_10_1 $THEN  -- selection directive begins
    $ERROR 'unsupported database release' $END  -- error directive
  $ELSE
    DBMS_OUTPUT.PUT_LINE (
      'Release ' || DBMS_DB_VERSION.VERSION || '.' ||
      DBMS_DB_VERSION.RELEASE || ' is supported.'
    );
  -- This COMMIT syntax is newly supported in 10.2:
  COMMIT WRITE IMMEDIATE NOWAIT;
  $END  -- selection directive ends
END;
/
 

Result:

Release 11.1 is supported.

Example 2-59 sets the values of the user-defined inquiry directives $$my_debug and $$my_tracing and then uses conditional compilation:

  • In the specification of package my_pkg, to determine the base type of the subtype my_real (BINARY_DOUBLE is available only for Oracle Database versions 10g and later.)

  • In the body of package my_pkg, to compute the values of my_pi and my_e differently for different database versions

  • In the procedure circle_area, to compile some code only if the inquiry directive $$my_debug has the value TRUE.

Example 2-59 Compiling Different Code for Different Database Versions

ALTER SESSION SET PLSQL_CCFLAGS = 'my_debug:FALSE, my_tracing:FALSE';
 
CREATE OR REPLACE PACKAGE my_pkg AS
  SUBTYPE my_real IS
    $IF DBMS_DB_VERSION.VERSION < 10 $THEN
      NUMBER;
    $ELSE
      BINARY_DOUBLE;
    $END
  
  my_pi my_real;
  my_e  my_real;
END my_pkg;
/
 
CREATE OR REPLACE PACKAGE BODY my_pkg AS
BEGIN
  $IF DBMS_DB_VERSION.VERSION < 10 $THEN
    my_pi := 3.14159265358979323846264338327950288420;
    my_e  := 2.71828182845904523536028747135266249775;
  $ELSE
    my_pi := 3.14159265358979323846264338327950288420d;
    my_e  := 2.71828182845904523536028747135266249775d;
  $END
END my_pkg;
/
 
CREATE OR REPLACE PROCEDURE circle_area(radius my_pkg.my_real) IS
  my_area       my_pkg.my_real;
  my_data_type  VARCHAR2(30);
BEGIN
  my_area := my_pkg.my_pi * (radius**2);
  
  DBMS_OUTPUT.PUT_LINE
    ('Radius: ' || TO_CHAR(radius) || ' Area: ' || TO_CHAR(my_area));
  
  $IF $$my_debug $THEN
    SELECT DATA_TYPE INTO my_data_type
    FROM USER_ARGUMENTS
    WHERE OBJECT_NAME = 'CIRCLE_AREA'
    AND ARGUMENT_NAME = 'RADIUS';
 
    DBMS_OUTPUT.PUT_LINE
      ('Data type of the RADIUS argument is: ' || my_data_type);
  $END
END;
/

Retrieving and Printing Post-Processed Source Text

The DBMS_PREPROCESSOR package provides subprograms that retrieve and print the source text of a PL/SQL unit in its post-processed form. For information about the DBMS_PREPROCESSOR package, see Oracle Database PL/SQL Packages and Types Reference.

Example 2-60 invokes the procedure DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCE to print the post-processed form of my_pkg (from Example 2-59). Lines of code in Example 2-59 that are not included in the post-processed text appear as blank lines.

Example 2-60 Displaying Post-Processed Source Code

CALL DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCE (
  'PACKAGE', 'HR', 'MY_PKG'
);

Result:

PACKAGE my_pkg AS
SUBTYPE my_real IS
BINARY_DOUBLE;
my_pi my_real;
my_e my_real;
END my_pkg;

Conditional Compilation Directive Restrictions

A conditional compilation directive cannot appear in the specification of a schema-level user-defined type (created with the "CREATE TYPE Statement"). This type specification specifies the attribute structure of the type, which determines the attribute structure of dependent types and the column structure of dependent tables.

Caution:

Using a conditional compilation directive to change the attribute structure of a type can cause dependent objects to "go out of sync" or dependent tables to become inaccessible. Oracle recommends that you change the attribute structure of a type only with the "ALTER TYPE Statement". The ALTER TYPE statement propagates changes to dependent objects.

The SQL parser imposes these restrictions on the location of the first conditional compilation directive in a stored PL/SQL unit or anonymous block:

  • In a package specification, a package body, a type body, and in a schema-level subprogram with no formal parameters, the first conditional compilation directive cannot appear before the keyword IS or AS.

  • In a schema-level subprogram with at least one formal parameter, the first conditional compilation directive cannot appear before the left parenthesis that follows the subprogram name.

    This example is correct:

    CREATE OR REPLACE PROCEDURE my_proc (
      $IF $$xxx $THEN i IN PLS_INTEGER $ELSE i IN INTEGER $END
    ) IS BEGIN NULL; END my_proc;
    /
    
  • In a trigger or an anonymous block, the first conditional compilation directive cannot appear before the keyword DECLARE or BEGIN, whichever comes first.

The SQL parser also imposes this restriction: If an anonymous block uses a placeholder, the placeholder cannot appear in a conditional compilation directive. For example:

BEGIN
  :n := 1; -- valid use of placeholder
  $IF ... $THEN
    :n := 1; -- invalid use of placeholder
$END