pl sql document by mv

120
PL SQL Document 1 PL SQL DOCUMENTATION ON DYNAMIC SQL, SEND MAIL, FOR ALL, FOR UPDATE BY Mahesh M. Vishwekar Oracle Apps Technical Developer Surmani Office Complex, D.P. Road, Aundh, Pune - 7 O: 001 267.... & +9120 40... / M: 879.616.4608 www.saturninfotech.com | [email protected] Oracle Gold Partner www.saturninfotech.com

Upload: mahhyvish

Post on 04-Apr-2015

371 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Pl SQL Document by Mv

PL SQL Document 1

PL SQL DOCUMENTATION

ON

DYNAMIC SQL,

SEND MAIL,

FOR ALL,

FOR UPDATE

BY

Mahesh M. Vishwekar

Oracle Apps Technical Developer  Surmani Office Complex,

D.P. Road, Aundh, Pune - 7 O:  001 267.... &  +9120 40... / M: 879.616.4608

www.saturninfotech.com | [email protected]

Oracle Gold Partner

www.saturninfotech.com

Page 2: Pl SQL Document by Mv

PL SQL Document 2

INDEX -

SR NO TITLE PAGE_NO.

1 Coding Dynamic SQL Statements - 3

2 Send mail from PL/SQL - 22

UTL_SMTP - 32 UTL_TCP - 59 UTL_URL - 81

3 PL SQL For All Operator - 87

4 Select For Updates in Cursors - 90

www.saturninfotech.com

Page 3: Pl SQL Document by Mv

PL SQL Document 3

Coding Dynamic SQL Statements

Dynamic SQL is a programming technique that enables you to build SQL statements dynamically at runtime. You can create more general purpose, flexible applications by using dynamic SQL because the full text of a SQL statement may be unknown at compilation. For example, dynamic SQL lets you create a procedure that operates on a table whose name is not known until runtime.

Oracle includes two ways to implement dynamic SQL in a PL/SQL application:

Native dynamic SQL, where you place dynamic SQL statements directly into PL/SQL blocks. Calling procedures in the DBMS_SQL package.

This chapter covers the following topics:

"What Is Dynamic SQL?" "Why Use Dynamic SQL?" "A Dynamic SQL Scenario Using Native Dynamic SQL" "Choosing Between Native Dynamic SQL and the DBMS_SQL Package" "Using Dynamic SQL in Languages Other Than PL/SQL" "Using PL/SQL Records in SQL INSERT and UPDATE Statements"

What Is Dynamic SQL?

Dynamic SQL enables you to write programs that reference SQL statements whose full text is not known until runtime. Before discussing dynamic SQL in detail, a clear definition of static SQL may provide a good starting point for understanding dynamic SQL. Static SQL statements do not change from execution to execution. The full text of static SQL statements are known at compilation, which provides the following benefits:

Successful compilation verifies that the SQL statements reference valid database objects. Successful compilation verifies that the necessary privileges are in place to access the database

objects. Performance of static SQL is generally better than dynamic SQL.

Because of these advantages, you should use dynamic SQL only if you cannot use static SQL to accomplish your goals, or if using static SQL is cumbersome compared to dynamic SQL. However, static SQL has limitations that can be overcome with dynamic SQL. You may not always know the full text of the SQL statements that must be executed in a PL/SQL procedure. Your program may accept user input that defines the SQL statements to execute, or your program may need to complete some processing work to determine the correct course of action. In such cases, you should use dynamic SQL.

For example, a reporting application in a data warehouse environment might not know the exact table name until runtime. These tables might be named according to the starting month and year

www.saturninfotech.com

Page 4: Pl SQL Document by Mv

PL SQL Document 4

of the quarter, for example INV_01_1997, INV_04_1997, INV_07_1997, INV_10_1997, INV_01_1998, and so on. You can use dynamic SQL in your reporting application to specify the table name at runtime.

You might also want to run a complex query with a user-selectable sort order. Instead of coding the query twice, with different ORDER BY clauses, you can construct the query dynamically to include a specified ORDER BY clause.

Dynamic SQL programs can handle changes in data definitions, without the need to recompile. This makes dynamic SQL much more flexible than static SQL. Dynamic SQL lets you write reusable code because the SQL can be easily adapted for different environments..

Dynamic SQL also lets you execute data definition language (DDL) statements and other SQL statements that are not supported in purely static SQL programs.

Why Use Dynamic SQL?

You should use dynamic SQL in cases where static SQL does not support the operation you want to perform, or in cases where you do not know the exact SQL statements that must be executed by a PL/SQL procedure. These SQL statements may depend on user input, or they may depend on processing work done by the program. The following sections describe typical situations where you should use dynamic SQL and typical problems that can be solved by using dynamic SQL

Executing DDL and SCL Statements in PL/SQL

In PL/SQL, you can only execute the following types of statements using dynamic SQL, rather than static SQL:

Data definition language (DDL) statements, such as CREATE, DROP, GRANT, and REVOKE Session control language (SCL) statements, such as ALTER SESSION and SET ROLE

See Also:

Oracle9i SQL Reference for information about DDL and SCL statements.

Also, you can only use the TABLE clause in the SELECT statement through dynamic SQL. For example, the following PL/SQL block contains a SELECT statement that uses the TABLE clause and native dynamic SQL:

CREATE TYPE t_emp AS OBJECT (id NUMBER, name VARCHAR2(20))/CREATE TYPE t_emplist AS TABLE OF t_emp/

CREATE TABLE dept_new (id NUMBER, emps t_emplist)

www.saturninfotech.com

Page 5: Pl SQL Document by Mv

PL SQL Document 5

NESTED TABLE emps STORE AS emp_table;

INSERT INTO dept_new VALUES ( 10, t_emplist( t_emp(1, 'SCOTT'), t_emp(2, 'BRUCE')));

DECLARE deptid NUMBER; ename VARCHAR2(20);BEGIN EXECUTE IMMEDIATE 'SELECT d.id, e.name FROM dept_new d, TABLE(d.emps) e -- not allowed in static SQL -- in PL/SQL WHERE e.id = 1' INTO deptid, ename;END;/

Executing Dynamic Queries

You can use dynamic SQL to create applications that execute dynamic queries, whose full text is not known until runtime. Many types of applications need to use dynamic queries, including:

Applications that allow users to input or choose query search or sorting criteria at runtime Applications that allow users to input or choose optimizer hints at run time Applications that query a database where the data definitions of tables are constantly changing Applications that query a database where new tables are created often

For examples, see "Querying Using Dynamic SQL: Example", and see the query examples in "A Dynamic SQL Scenario Using Native Dynamic SQL".

Referencing Database Objects that Do Not Exist at Compilation

Many types of applications must interact with data that is generated periodically. For example, you might know the tables definitions at compile time, but not the names of the tables.

Dynamic SQL can solve this problem, because it lets you wait until runtime to specify the table names. For example, in the sample data warehouse application discussed in "What Is Dynamic SQL?", new tables are generated every quarter, and these tables always have the same definition. You might let a user specify the name of the table at runtime with a dynamic SQL query similar to the following:

CREATE OR REPLACE PROCEDURE query_invoice( month VARCHAR2, year VARCHAR2) IS TYPE cur_typ IS REF CURSOR; c cur_typ; query_str VARCHAR2(200);

www.saturninfotech.com

Page 6: Pl SQL Document by Mv

PL SQL Document 6

inv_num NUMBER; inv_cust VARCHAR2(20); inv_amt NUMBER;BEGIN query_str := 'SELECT num, cust, amt FROM inv_' || month ||'_'|| year || ' WHERE invnum = :id'; OPEN c FOR query_str USING inv_num; LOOP FETCH c INTO inv_num, inv_cust, inv_amt; EXIT WHEN c%NOTFOUND; -- process row here END LOOP; CLOSE c;END;/

Optimizing Execution Dynamically

You can use dynamic SQL to build a SQL statement in a way that optimizes the execution by concatenating the hints into a SQL statement dynamically. This lets you change the hints based on your current database statistics, without requiring recompilation.

For example, the following procedure uses a variable called a_hint to allow users to pass a hint option to the SELECT statement:

CREATE OR REPLACE PROCEDURE query_emp (a_hint VARCHAR2) AS TYPE cur_typ IS REF CURSOR; c cur_typ;BEGIN OPEN c FOR 'SELECT ' || a_hint || ' empno, ename, sal, job FROM emp WHERE empno = 7566'; -- processEND;/

In this example, the user can pass any of the following values for a_hint:

a_hint = '/*+ ALL_ROWS */'

a_hint = '/*+ FIRST_ROWS */'

a_hint = '/*+ CHOOSE */'

or any other valid hint option.

See Also:

Oracle9i Database Performance Guide and Reference for more information about using hints.

www.saturninfotech.com

Page 7: Pl SQL Document by Mv

PL SQL Document 7

Executing Dynamic PL/SQL Blocks

You can use the EXECUTE IMMEDIATE statement to execute anonymous PL/SQL blocks. You can add flexibility by constructing the block contents at runtime.

For example, suppose ythroughthroughou want to write an application that takes an event number and dispatches to a handler for the event. The name of the handler is in the form EVENT_HANDLER_event_num, where event_num is the number of the event. One approach is to implement the dispatcher as a switch statement, where the code handles each event by making a static call to its appropriate handler. This code is not very extensible because the dispatcher code must be updated whenever a handler for a new event is added.

CREATE OR REPLACE PROCEDURE event_handler_1(param number) AS BEGIN -- process event RETURN; END;/

CREATE OR REPLACE PROCEDURE event_handler_2(param number) AS BEGIN -- process event RETURN; END;/

CREATE OR REPLACE PROCEDURE event_handler_3(param number) AS BEGIN -- process event RETURN; END;/

CREATE OR REPLACE PROCEDURE event_dispatcher (event number, param number) ISBEGIN IF (event = 1) THEN EVENT_HANDLER_1(param); ELSIF (event = 2) THEN EVENT_HANDLER_2(param); ELSIF (event = 3) THEN EVENT_HANDLER_3(param); END IF;END;/

Using native dynamic SQL, you can write a smaller, more flexible event dispatcher similar to the following:

CREATE OR REPLACE PROCEDURE event_dispatcher (event NUMBER, param NUMBER) ISBEGIN EXECUTE IMMEDIATE 'BEGIN

www.saturninfotech.com

Page 8: Pl SQL Document by Mv

PL SQL Document 8

EVENT_HANDLER_' || to_char(event) || '(:1); END;' USING param;END;/

Performing Dynamic Operations Using Invoker-Rights

By using the invoker-rights feature with dynamic SQL, you can build applications that issue dynamic SQL statements under the privileges and schema of the invoker. These two features, invoker-rights and dynamic SQL, enable you to build reusable application subcomponents that can operate on and access the invoker's data and modules.

See Also:

PL/SQL User's Guide and Reference for information about using invokers-rights and native dynamic SQL.

A Dynamic SQL Scenario Using Native Dynamic SQL

This scenario shows you how to perform the following operations using native dynamic SQL:

Execute DDL and DML operations Execute single row and multiple row queries

The database in this scenario is a company's human resources database (named hr) with the following data model:

A master table named offices contains the list of all company locations. The offices table has the following definition:

Column Name Null? Type LOCATION NOT_NULL VARCHAR2(200)

Multiple emp_location tables contain the employee information, where location is the name of city where the office is located. For example, a table named emp_houston contains employee information for the company's Houston office, while a table named emp_boston contains employee information for the company's Boston office.

Each emp_location table has the following definition:

Column Name Null? Type EMPNO NOT_NULL NUMBER(4)ENAME NOT_NULL VARCHAR2(10)JOB NOT_NULL VARCHAR2(9)SAL NOT_NULL NUMBER(7,2)

www.saturninfotech.com

Page 9: Pl SQL Document by Mv

PL SQL Document 9

DEPTNO NOT_NULL NUMBER(2)

The following sections describe various native dynamic SQL operations that can be performed on the data in the hr database.

Sample DML Operation Using Native Dynamic SQL

The following native dynamic SQL procedure gives a raise to all employees with a particular job title:

CREATE OR REPLACE PROCEDURE salary_raise (raise_percent NUMBER, job VARCHAR2) IS TYPE loc_array_type IS TABLE OF VARCHAR2(40) INDEX BY binary_integer; dml_str VARCHAR2 (200); loc_array loc_array_type;BEGIN -- bulk fetch the list of office locations SELECT location BULK COLLECT INTO loc_array FROM offices; -- for each location, give a raise to employees with the given 'job' FOR i IN loc_array.first..loc_array.last LOOP dml_str := 'UPDATE emp_' || loc_array(i) || ' SET sal = sal * (1+(:raise_percent/100))' || ' WHERE job = :job_title'; EXECUTE IMMEDIATE dml_str USING raise_percent, job; END LOOP;END;/SHOW ERRORS;

Sample DDL Operation Using Native Dynamic SQL

The EXECUTE IMMEDIATE statement can perform DDL operations. For example, the following procedure adds an office location:

CREATE OR REPLACE PROCEDURE add_location (loc VARCHAR2) ISBEGIN -- insert new location in master table INSERT INTO offices VALUES (loc); -- create an employee information table EXECUTE IMMEDIATE 'CREATE TABLE ' || 'emp_' || loc || '( empno NUMBER(4) NOT NULL, ename VARCHAR2(10), job VARCHAR2(9), sal NUMBER(7,2), deptno NUMBER(2) )';END;

www.saturninfotech.com

Page 10: Pl SQL Document by Mv

PL SQL Document 10

/SHOW ERRORS;

The following procedure deletes an office location:

CREATE OR REPLACE PROCEDURE drop_location (loc VARCHAR2) ISBEGIN -- delete the employee table for location 'loc' EXECUTE IMMEDIATE 'DROP TABLE ' || 'emp_' || loc; -- remove location from master table DELETE FROM offices WHERE location = loc;END;/SHOW ERRORS;

Sample Single-Row Query Using Native Dynamic SQL

The EXECUTE IMMEDIATE statement can perform dynamic single-row queries. You can specify bind variables in the USING clause and fetch the resulting row into the target specified in the INTO clause of the statement.

The following function retrieves the number of employees at a particular location performing a specified job:

CREATE OR REPLACE FUNCTION get_num_of_employees (loc VARCHAR2, job VARCHAR2) RETURN NUMBER IS query_str VARCHAR2(1000); num_of_employees NUMBER;BEGIN query_str := 'SELECT COUNT(*) FROM ' || ' emp_' || loc || ' WHERE job = :job_title'; EXECUTE IMMEDIATE query_str INTO num_of_employees USING job; RETURN num_of_employees;END;/SHOW ERRORS;

Sample Multiple-Row Query Using Native Dynamic SQL

The OPEN-FOR, FETCH, and CLOSE statements can perform dynamic multiple-row queries. For example, the following procedure lists all of the employees with a particular job at a specified location:

CREATE OR REPLACE PROCEDURE list_employees(loc VARCHAR2, job VARCHAR2) IS TYPE cur_typ IS REF CURSOR;

www.saturninfotech.com

Page 11: Pl SQL Document by Mv

PL SQL Document 11

c cur_typ; query_str VARCHAR2(1000); emp_name VARCHAR2(20); emp_num NUMBER;BEGIN query_str := 'SELECT ename, empno FROM emp_' || loc || ' WHERE job = :job_title'; -- find employees who perform the specified job OPEN c FOR query_str USING job; LOOP FETCH c INTO emp_name, emp_num; EXIT WHEN c%NOTFOUND; -- process row here END LOOP; CLOSE c;END;/SHOW ERRORS;

Choosing Between Native Dynamic SQL and the DBMS_SQL Package

Oracle provides two methods for using dynamic SQL within PL/SQL: native dynamic SQL and the DBMS_SQL package. Native dynamic SQL lets you place dynamic SQL statements directly into PL/SQL code. These dynamic statements include DML statements (including queries), PL/SQL anonymous blocks, DDL statements, transaction control statements, and session control statements.

To process most native dynamic SQL statements, you use the EXECUTE IMMEDIATE statement. To process a multi-row query (SELECT statement), you use OPEN-FOR, FETCH, and CLOSE statements.

Note:

To use native dynamic SQL, the COMPATIBLE initialization parameter must be set to 8.1.0 or higher. See Oracle9i Database Migration for more information about the COMPATIBLE parameter.

The DBMS_SQL package is a PL/SQL library that offers an API to execute SQL statements dynamically. The DBMS_SQL package has procedures to open a cursor, parse a cursor, supply binds, and so on. Programs that use the DBMS_SQL package make calls to this package to perform dynamic SQL operations.

www.saturninfotech.com

Page 12: Pl SQL Document by Mv

PL SQL Document 12

The following sections provide detailed information about the advantages of both methods.

See Also:

The PL/SQL User's Guide and Reference for detailed information about using native dynamic SQL and the Oracle9i Supplied PL/SQL Packages and Types Reference for detailed information about using the DBMS_SQL package. In the PL/SQL User's Guide and Reference, native dynamic SQL is referred to simply as dynamic SQL.

Advantages of Native Dynamic SQL

Native dynamic SQL provides the following advantages over the DBMS_SQL package:

Native Dynamic SQL is Easy to Use

Because native dynamic SQL is integrated with SQL, you can use it in the same way that you use static SQL within PL/SQL code. Native dynamic SQL code is typically more compact and readable than equivalent code that uses the DBMS_SQL package.

With the DBMS_SQL package you must call many procedures and functions in a strict sequence, making even simple operations require a lot of code. You can avoid this complexity by using native dynamic SQL instead.

Table   8-1 illustrates the difference in the amount of code required to perform the same operation using the DBMS_SQL package and native dynamic SQL.

Table 8-1 Code Comparison of DBMS_SQL Package and Native Dynamic SQL

DBMS_SQL Package Native Dynamic SQL

CREATE PROCEDURE insert_into_table ( table_name VARCHAR2, deptnumber NUMBER, deptname VARCHAR2, location VARCHAR2) IS cur_hdl INTEGER; stmt_str VARCHAR2(200); rows_processed BINARY_INTEGER;

BEGIN stmt_str := 'INSERT INTO ' || table_name || ' VALUES (:deptno, :dname, :loc)';

-- open cursor cur_hdl := dbms_sql.open_cursor;

-- parse cursor

CREATE PROCEDURE insert_into_table ( table_name VARCHAR2, deptnumber NUMBER, deptname VARCHAR2, location VARCHAR2) IS stmt_str VARCHAR2(200);

BEGIN stmt_str := 'INSERT INTO ' || table_name || ' values (:deptno, :dname, :loc)';

EXECUTE IMMEDIATE stmt_str USING deptnumber, deptname, location;

END;/

www.saturninfotech.com

Page 13: Pl SQL Document by Mv

PL SQL Document 13

DBMS_SQL Package Native Dynamic SQL

dbms_sql.parse(cur_hdl, stmt_str, dbms_sql.native);

-- supply binds dbms_sql.bind_variable (cur_hdl, ':deptno', deptnumber); dbms_sql.bind_variable (cur_hdl, ':dname', deptname); dbms_sql.bind_variable (cur_hdl, ':loc', location);

-- execute cursor rows_processed := dbms_sql.execute(cur_hdl);

-- close cursor dbms_sql.close_cursor(cur_hdl);

END;/SHOW ERRORS;

SHOW ERRORS;

Native Dynamic SQL is Faster than DBMS_SQL

Native dynamic SQL in PL/SQL performs comparably to the performance of static SQL, because the PL/SQL interpreter has built-in support for it. Programs that use native dynamic SQL are much faster than programs that use the DBMS_SQL package. Typically, native dynamic SQL statements perform 1.5 to 3 times better than equivalent DBMS_SQL calls. (Your performance gains may vary depending on your application.)

Native dynamic SQL bundles the statement preparation, binding, and execution steps into a single operation, which minimizes the data copying and procedure call overhead and improves performance.

The DBMS_SQL package is based on a procedural API and incurs high procedure call and data copy overhead. Each time you bind a variable, the DBMS_SQL package copies the PL/SQL bind variable into its space for use during execution. Each time you execute a fetch, the data is copied into the space managed by the DBMS_SQL package and then the fetched data is copied, one column at a time, into the appropriate PL/SQL variables, resulting in substantial overhead.

www.saturninfotech.com

Page 14: Pl SQL Document by Mv

PL SQL Document 14

Performance Tip: Using Bind Variables

When using either native dynamic SQL or the DBMS_SQL package, you can improve performance by using bind variables, because bind variables allow Oracle to share a single cursor for multiple SQL statements.

For example, the following native dynamic SQL code does not use bind variables:

CREATE OR REPLACE PROCEDURE del_dept ( my_deptno dept.deptno%TYPE) ISBEGIN EXECUTE IMMEDIATE 'DELETE FROM dept WHERE deptno = ' || to_char (my_deptno);END;/SHOW ERRORS;

For each distinct my_deptno variable, a new cursor is created, causing resource contention and poor performance. Instead, bind my_deptno as a bind variable:

CREATE OR REPLACE PROCEDURE del_dept ( my_deptno dept.deptno%TYPE) ISBEGIN EXECUTE IMMEDIATE 'DELETE FROM dept WHERE deptno = :1' USING my_deptno;END;/SHOW ERRORS;

Here, the same cursor is reused for different values of the bind my_deptno, improving performance and scalabilty.

Native Dynamic SQL Supports User-Defined Types

Native dynamic SQL supports all of the types supported by static SQL in PL/SQL, including user-defined types such as user-defined objects, collections, and REFs. The DBMS_SQL package does not support these user-defined types.

Note:

The DBMS_SQL package provides limited support for arrays. See the Oracle9i Supplied PL/SQL Packages and Types Reference for information.

www.saturninfotech.com

Page 15: Pl SQL Document by Mv

PL SQL Document 15

Native Dynamic SQL Supports Fetching Into Records

Native dynamic SQL and static SQL both support fetching into records, but the DBMS_SQL package does not. With native dynamic SQL, the rows resulting from a query can be directly fetched into PL/SQL records.

In the following example, the rows from a query are fetched into the emp_rec record:

DECLARE TYPE EmpCurTyp IS REF CURSOR; c EmpCurTyp; emp_rec emp%ROWTYPE; stmt_str VARCHAR2(200); e_job emp.job%TYPE;

BEGIN stmt_str := 'SELECT * FROM emp WHERE job = :1'; -- in a multi-row query OPEN c FOR stmt_str USING 'MANAGER'; LOOP FETCH c INTO emp_rec; EXIT WHEN c%NOTFOUND; END LOOP; CLOSE c; -- in a single-row query EXECUTE IMMEDIATE stmt_str INTO emp_rec USING 'PRESIDENT';

END;/

Advantages of the DBMS_SQL Package

The DBMS_SQL package provides the following advantages over native dynamic SQL:

DBMS_SQL is Supported in Client-Side Programs

The DBMS_SQL package is supported in client-side programs, but native dynamic SQL is not. Every call to the DBMS_SQL package from the client-side program translates to a PL/SQL remote procedure call (RPC); these calls occur when you need to bind a variable, define a variable, or execute a statement.

DBMS_SQL Supports DESCRIBE

The DESCRIBE_COLUMNS procedure in the DBMS_SQL package can be used to describe the columns for a cursor opened and parsed through DBMS_SQL. This feature is similar to the DESCRIBE command in SQL*Plus. Native dynamic SQL does not have a DESCRIBE facility.

www.saturninfotech.com

Page 16: Pl SQL Document by Mv

PL SQL Document 16

DBMS_SQL Supports Multiple Row Updates and Deletes with a RETURNING Clause

The DBMS_SQL package supports statements with a RETURNING clause that update or delete multiple rows. Native dynamic SQL only supports a RETURNING clause if a single row is returned.

See Also:

"Performing DML with RETURNING Clause Using Dynamic SQL: Example" for examples of DBMS_SQL package code and native dynamic SQL code that uses a RETURNING clause.

DBMS_SQL Supports SQL Statements Larger than 32KB

The DBMS_SQL package supports SQL statements larger than 32KB; native dynamic SQL does not.

DBMS_SQL Lets You Reuse SQL Statements

The PARSE procedure in the DBMS_SQL package parses a SQL statement once. After the initial parsing, you can use the statement multiple times with different sets of bind arguments.

Native dynamic SQL prepares a SQL statement each time the statement is used, which typically involves parsing, optimization, and plan generation. Although the extra prepare operations incur a small performance penalty, the slowdown is typically outweighed by the performance benefits of native dynamic SQL.

Examples of DBMS_SQL Package Code and Native Dynamic SQL Code

The following examples illustrate the differences in the code necessary to complete operations with the DBMS_SQL package and native dynamic SQL. Specifically, the following types of examples are presented:

A query A DML operation A DML returning operation

In general, the native dynamic SQL code is more readable and compact, which can improve developer productivity.

Querying Using Dynamic SQL: Example

The following example includes a dynamic query statement with one bind variable (:jobname) and two select columns (ename and sal):

www.saturninfotech.com

Page 17: Pl SQL Document by Mv

PL SQL Document 17

stmt_str := 'SELECT ename, sal FROM emp WHERE job = :jobname';

This example queries for employees with the job description SALESMAN in the job column of the emp table. Table   8-2 shows sample code that accomplishes this query using the DBMS_SQL package and native dynamic SQL.

Table 8-2 Querying Using the DBMS_SQL Package and Native Dynamic SQL

DBMS_SQL Query Operation Native Dynamic SQL Query Operation

DECLARE stmt_str varchar2(200); cur_hdl int; rows_processed int; name varchar2(10); salary int;BEGINcur_hdl := dbms_sql.open_cursor; -- open cursor stmt_str := 'SELECT ename, sal FROM emp WHERE job = :jobname';dbms_sql.parse(cur_hdl, stmt_str, dbms_sql.native);

-- supply binds (bind by name) dbms_sql.bind_variable( cur_hdl, 'jobname', 'SALESMAN');

-- describe defines dbms_sql.define_column(cur_hdl, 1, name, 200); dbms_sql.define_column(cur_hdl, 2, salary);

rows_processed := dbms_sql.execute(cur_hdl); -- execute

LOOP -- fetch a row IF dbms_sql.fetch_rows(cur_hdl) > 0 then

-- fetch columns from the row dbms_sql.column_value(cur_hdl, 1, name); dbms_sql.column_value(cur_hdl, 2, salary);

-- <process data>

ELSE EXIT;

DECLARE TYPE EmpCurTyp IS REF CURSOR; cur EmpCurTyp; stmt_str VARCHAR2(200); name VARCHAR2(20); salary NUMBER;BEGIN stmt_str := 'SELECT ename, sal FROM emp WHERE job = :1'; OPEN cur FOR stmt_str USING 'SALESMAN';

LOOP FETCH cur INTO name, salary; EXIT WHEN cur%NOTFOUND; -- <process data> END LOOP; CLOSE cur;END;/

www.saturninfotech.com

Page 18: Pl SQL Document by Mv

PL SQL Document 18

DBMS_SQL Query Operation Native Dynamic SQL Query Operation

END IF; END LOOP; dbms_sql.close_cursor(cur_hdl); -- close cursorEND;/

Performing DML Using Dynamic SQL: Example

The following example includes a dynamic INSERT statement for a table with three columns:

stmt_str := 'INSERT INTO dept_new VALUES (:deptno, :dname, :loc)';

This example inserts a new row for which the column values are in the PL/SQL variables deptnumber, deptname, and location. Table   8-3 shows sample code that accomplishes this DML operation using the DBMS_SQL package and native dynamic SQL.

Table 8-3 DML Operation Using the DBMS_SQL Package and Native Dynamic SQL

DBMS_SQL DML Operation Native Dynamic SQL DML Operation

DECLARE stmt_str VARCHAR2(200); cur_hdl NUMBER; deptnumber NUMBER := 99; deptname VARCHAR2(20); location VARCHAR2(10); rows_processed NUMBER;BEGIN stmt_str := 'INSERT INTO dept_new VALUES (:deptno, :dname, :loc)'; cur_hdl := DBMS_SQL.OPEN_CURSOR; DBMS_SQL.PARSE( cur_hdl, stmt_str, DBMS_SQL.NATIVE); -- supply binds DBMS_SQL.BIND_VARIABLE (cur_hdl, ':deptno', deptnumber); DBMS_SQL.BIND_VARIABLE (cur_hdl, ':dname', deptname); DBMS_SQL.BIND_VARIABLE (cur_hdl, ':loc', location); rows_processed := dbms_sql.execute(cur_hdl); -- execute DBMS_SQL.CLOSE_CURSOR(cur_hdl); -- closeEND;/

DECLARE stmt_str VARCHAR2(200); deptnumber NUMBER := 99; deptname VARCHAR2(20); location VARCHAR2(10);BEGIN stmt_str := 'INSERT INTO dept_new VALUES (:deptno, :dname, :loc)'; EXECUTE IMMEDIATE stmt_str USING deptnumber, deptname, location;END;/

www.saturninfotech.com

Page 19: Pl SQL Document by Mv

PL SQL Document 19

Performing DML with RETURNING Clause Using Dynamic SQL: Example

The following example uses a dynamic UPDATE statement to update the location of a department, then returns the name of the department:

stmt_str := 'UPDATE dept_new SET loc = :newloc WHERE deptno = :deptno RETURNING dname INTO :dname';

Table   8-4 shows sample code that accomplishes this operation using both the DBMS_SQL package and native dynamic SQL.

Table 8-4 DML Returning Operation Using the DBMS_SQL Package and Native Dynamic SQL

DBMS_SQL DML Returning OperationNative Dynamic SQL DML Returning Operation

DECLARE deptname_array dbms_sql.Varchar2_Table; cur_hdl INT; stmt_str VARCHAR2(200); location VARCHAR2(20); deptnumber NUMBER := 10; rows_processed NUMBER;BEGIN stmt_str := 'UPDATE dept_new SET loc = :newloc WHERE deptno = :deptno RETURNING dname INTO :dname'; cur_hdl := dbms_sql.open_cursor; dbms_sql.parse (cur_hdl, stmt_str, dbms_sql.native); -- supply binds dbms_sql.bind_variable (cur_hdl, ':newloc', location); dbms_sql.bind_variable (cur_hdl, ':deptno', deptnumber); dbms_sql.bind_array (cur_hdl, ':dname', deptname_array); -- execute cursor rows_processed := dbms_sql.execute(cur_hdl); -- get RETURNING column into OUT bind array dbms_sql.variable_value (cur_hdl, ':dname', deptname_array);

DECLARE deptname_array dbms_sql.Varchar2_Table; stmt_str VARCHAR2(200); location VARCHAR2(20); deptnumber NUMBER := 10; deptname VARCHAR2(20);BEGIN stmt_str := 'UPDATE dept_new SET loc = :newloc WHERE deptno = :deptno RETURNING dname INTO :dname'; EXECUTE IMMEDIATE stmt_str USING location, deptnumber, OUT deptname;END;/

www.saturninfotech.com

Page 20: Pl SQL Document by Mv

PL SQL Document 20

DBMS_SQL DML Returning OperationNative Dynamic SQL DML Returning Operation

dbms_sql.close_cursor(cur_hdl); END;/

Using Dynamic SQL in Languages Other Than PL/SQL

Although this chapter discusses PL/SQL support for dynamic SQL, you can call dynamic SQL from other languages:

If you use C/C++, you can call dynamic SQL with the Oracle Call Interface (OCI), or you can use the Pro*C/C++ precompiler to add dynamic SQL extensions to your C code.

If you use COBOL, you can use the Pro*COBOL precompiler to add dynamic SQL extensions to your COBOL code.

If you use Java, you can develop applications that use dynamic SQL with JDBC.

If you have an application that uses OCI, Pro*C/C++, or Pro*COBOL to execute dynamic SQL, you should consider switching to native dynamic SQL inside PL/SQL stored procedures and functions. The network round-trips required to perform dynamic SQL operations from client-side applications might hurt performance. Stored procedures can reside on the server, eliminating the network overhead. You can call the PL/SQL stored procedures and stored functions from the OCI, Pro*C/C++, or Pro*COBOL application.

See Also:

For information about calling Oracle stored procedures and stored functions from various languages, refer to:

Oracle Call Interface Programmer's Guide Pro*C/C++ Precompiler Programmer's Guide Pro*COBOL Precompiler Programmer's Guide

www.saturninfotech.com

Page 21: Pl SQL Document by Mv

PL SQL Document 21

Oracle9i Java Stored Procedures Developer's Guide

Using PL/SQL Records in SQL INSERT and UPDATE Statements

Although you can enumerate each field of a PL/SQL record when inserting or updating rows in a table, the resulting code is not especially readable or maintainable. Instead, you can use PL/SQL records directly in these statements. The most convenient technique is to declare the record using a %ROWTYPE attribute, so that it has exactly the same fields as the SQL table.

DECLARE emp_rec emp%ROWTYPE;BEGIN emp_rec.eno := 1500; emp_rec.ename := 'Steven Hill'; emp_rec.sal := '40000';-- A %ROWTYPE value can fill in all the row fields. INSERT INTO emp VALUES emp_rec;

-- The fields of a %ROWTYPE can completely replace the table columns. UPDATE emp SET ROW = emp_rec WHERE eno = 100;END;/

Although this technique helps to integrate PL/SQL variables and types more closely with SQL DML statements, you cannot use PL/SQL records as bind variables in dynamic SQL statements.

www.saturninfotech.com

Page 22: Pl SQL Document by Mv

PL SQL Document 22

Send mail from PL/SQL

Sample scripts for sending E-mail messages from PL/SQL:

Starting from Oracle 8i release 8.1.6, one can send E-mail messages directly from PL/SQL using either the UTL_TCP or UTL_SMTP packages. However, Oracle introduced an improved package for sending E-mail in Oracle 10g - called UTL_MAIL - that should be used instead of UTL_SMTP.

All examples below require a working SMTP mail server. Customize these scripts to point the IP Address of your SMTP server. The SMTP port is usually 25. Configuring an SMTP server is not an Oracle function and thus out of scope for this site.

Send mail with UTL_MAIL

For security reasons, UTL_MAIL is not enabled by default. You must install it by connecting to SYS, then executing the utlmail.sql and prvtmail.plb scripts in the $ORACLE_HOME/rdbms/admin directory. In addition, you must configure an initialization parameter, SMTP_OUT_SERVER, to point to an outgoing SMTP server (unlike UTL_SMTP, this is not specified in the function arguments and must be pre-defined).

IMPORTANT: The scripts do not seem to grant the needed EXECUTE permission to PUBLIC. Thus, after running the scripts, while still logged in as SYS you should run the following line:

grant execute on UTL_MAIL to public;

Example:

BEGIN EXECUTE IMMEDIATE 'ALTER SESSION SET smtp_out_server = ''127.0.0.1'''; UTL_MAIL.send(sender => '[email protected]', recipients => '[email protected]', subject => 'Test Mail', message => 'Hello World', mime_type => 'text; charset=us-ascii');END;/

Send mail with UTL_SMTP

Send mail without attachments using the UTL_SMTP package:

DECLARE v_From VARCHAR2(80) := '[email protected]'; v_Recipient VARCHAR2(80) := '[email protected]'; v_Subject VARCHAR2(80) := 'test subject'; v_Mail_Host VARCHAR2(30) := 'mail.mycompany.com';

www.saturninfotech.com

Page 23: Pl SQL Document by Mv

PL SQL Document 23

v_Mail_Conn utl_smtp.Connection; crlf VARCHAR2(2)  := chr(13)||chr(10);BEGIN v_Mail_Conn := utl_smtp.Open_Connection(v_Mail_Host, 25); utl_smtp.Helo(v_Mail_Conn, v_Mail_Host); utl_smtp.Mail(v_Mail_Conn, v_From); utl_smtp.Rcpt(v_Mail_Conn, v_Recipient); utl_smtp.Data(v_Mail_Conn, 'Date: ' || to_char(sysdate, 'Dy, DD Mon YYYY hh24:mi:ss') || crlf || 'From: ' || v_From || crlf || 'Subject: '|| v_Subject || crlf || 'To: ' || v_Recipient || crlf || crlf || 'some message text'|| crlf || -- Message body 'more message text'|| crlf ); utl_smtp.Quit(v_mail_conn);EXCEPTION WHEN utl_smtp.Transient_Error OR utl_smtp.Permanent_Error then raise_application_error(-20000, 'Unable to send mail: '||sqlerrm);END;/

Send mail with UTL_SMTP - with attachments

Send mail with attachments using the UTL_SMTP package:

DECLARE v_From VARCHAR2(80) := '[email protected]'; v_Recipient VARCHAR2(80) := '[email protected]'; v_Subject VARCHAR2(80) := 'test subject'; v_Mail_Host VARCHAR2(30) := 'mail.mycompany.com'; v_Mail_Conn utl_smtp.Connection; crlf VARCHAR2(2)  := chr(13)||chr(10);BEGIN v_Mail_Conn := utl_smtp.Open_Connection(v_Mail_Host, 25);

utl_smtp.Helo(v_Mail_Conn, v_Mail_Host);

utl_smtp.Mail(v_Mail_Conn, v_From);

utl_smtp.Rcpt(v_Mail_Conn, v_Recipient);

utl_smtp.Data(v_Mail_Conn, 'Date: ' || to_char(sysdate, 'Dy, DD Mon YYYY hh24:mi:ss') || crlf || 'From: ' || v_From || crlf || 'Subject: '|| v_Subject || crlf || 'To: ' || v_Recipient || crlf ||

'MIME-Version: 1.0'|| crlf || -- Use MIME mail standard 'Content-Type: multipart/mixed;'|| crlf || ' boundary="-----SECBOUND"'|| crlf || crlf ||

www.saturninfotech.com

Page 24: Pl SQL Document by Mv

PL SQL Document 24

'-------SECBOUND'|| crlf || 'Content-Type: text/plain;'|| crlf || 'Content-Transfer_Encoding: 7bit'|| crlf || crlf || 'some message text'|| crlf || -- Message body 'more message text'|| crlf || crlf ||

'-------SECBOUND'|| crlf || 'Content-Type: text/plain;'|| crlf || ' name="excel.csv"'|| crlf || 'Content-Transfer_Encoding: 8bit'|| crlf || 'Content-Disposition: attachment;'|| crlf || ' filename="excel.csv"'|| crlf || crlf || 'CSV,file,attachement'|| crlf || -- Content of attachment crlf ||

'-------SECBOUND--' -- End MIME mail );

utl_smtp.Quit(v_mail_conn);EXCEPTION WHEN utl_smtp.Transient_Error OR utl_smtp.Permanent_Error then raise_application_error(-20000, 'Unable to send mail: '||sqlerrm);END;/

www.saturninfotech.com

Page 25: Pl SQL Document by Mv

PL SQL Document 25

Send mail with UTL_TCP

Send mail using the UTL_TCP package:

CREATE OR REPLACE PROCEDURE SEND_MAIL ( msg_from varchar2 := 'oracle', msg_to varchar2, msg_subject varchar2 := 'E-Mail message from your database', msg_text varchar2 := )IS c utl_tcp.connection; rc integer;BEGIN c := utl_tcp.open_connection('127.0.0.1', 25); -- open the SMTP port 25 on local machine dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'HELO localhost'); dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'MAIL FROM: '||msg_from); dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'RCPT TO: '||msg_to); dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'DATA'); -- Start message body dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'Subject: '||msg_subject); rc := utl_tcp.write_line(c, ); rc := utl_tcp.write_line(c, msg_text); rc := utl_tcp.write_line(c, '.'); -- End of message body dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'QUIT'); dbms_output.put_line(utl_tcp.get_line(c, TRUE)); utl_tcp.close_connection(c); -- Close the connectionEXCEPTION when others then raise_application_error( -20000, 'Unable to send e-mail message from pl/sql because of: '|| sqlerrm);END;/show errors-- Test it:set serveroutput on

exec send_mail(msg_to =>'[email protected]');

exec send_mail(msg_to =>'[email protected]', - msg_text=>'Look Ma, I can send mail from plsql' -

);

www.saturninfotech.com

Page 26: Pl SQL Document by Mv

PL SQL Document 26

Send mail with UTL_TCP - with attachments

Send e-mail messages with attachments from PL/SQL using UTL_TCP:

CREATE OR REPLACE PROCEDURE SEND_MAIL ( msg_from varchar2 := '[email protected]', ----- MAIL BOX SENDING THE EMAIL msg_to varchar2 := '[email protected]', ----- MAIL BOX RECIEVING THE EMAIL msg_subject varchar2 := 'Output file TEST1', ----- EMAIL SUBJECT msg_text varchar2 := 'THIS IS THE TEXT OF THE EMAIL MESSAGE.', v_output1 varchar2 := 'THIS IS THE TEXT OF THE ATTACHMENT FILE. THIS TEXT WILL BE IN A TEXT FILE ATTACHED TO THE EMAIL.')IS c utl_tcp.connection; rc integer; crlf VARCHAR2(2):= CHR(13)||CHR(10); mesg VARCHAR2(32767);BEGIN c := utl_tcp.open_connection('196.35.140.18', 25); ----- OPEN SMTP PORT CONNECTION rc := utl_tcp.write_line(c, 'HELO 196.35.140.18'); ----- PERFORMS HANDSHAKING WITH SMTP SERVER dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'EHLO 196.35.140.18'); ----- PERFORMS HANDSHAKING, INCLUDING EXTRA INFORMATION dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'MAIL FROM: '||msg_from); ----- MAIL BOX SENDING THE EMAIL dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'RCPT TO: '||msg_to); ----- MAIL BOX RECIEVING THE EMAIL dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'DATA'); ----- EMAIL MESSAGE BODY START dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'Date: '||TO_CHAR( SYSDATE, 'dd Mon yy hh24:mi:ss' )); rc := utl_tcp.write_line(c, 'From: '||msg_from||' <'||msg_from||'>'); rc := utl_tcp.write_line(c, 'MIME-Version: 1.0'); rc := utl_tcp.write_line(c, 'To: '||msg_to||' <'||msg_to||'>'); rc := utl_tcp.write_line(c, 'Subject: '||msg_subject); rc := utl_tcp.write_line(c, 'Content-Type: multipart/mixed;'); ----- INDICATES THAT THE BODY CONSISTS OF MORE THAN ONE PART rc := utl_tcp.write_line(c, ' boundary="-----SECBOUND"'); ----- SEPERATOR USED TO SEPERATE THE BODY PARTS rc := utl_tcp.write_line(c, ); ----- DO NOT REMOVE THIS BLANK LINE - PART OF MIME STANDARD rc := utl_tcp.write_line(c, '-------SECBOUND'); rc := utl_tcp.write_line(c, 'Content-Type: text/plain'); ----- 1ST BODY PART. EMAIL TEXT MESSAGE rc := utl_tcp.write_line(c, 'Content-Transfer-Encoding: 7bit');

www.saturninfotech.com

Page 27: Pl SQL Document by Mv

PL SQL Document 27

rc := utl_tcp.write_line(c, ); rc := utl_tcp.write_line(c, msg_text); ----- TEXT OF EMAIL MESSAGE rc := utl_tcp.write_line(c, ); rc := utl_tcp.write_line(c, '-------SECBOUND'); rc := utl_tcp.write_line(c, 'Content-Type: text/plain;'); ----- 2ND BODY PART. rc := utl_tcp.write_line(c, ' name="Test.txt"'); rc := utl_tcp.write_line(c, 'Content-Transfer_Encoding: 8bit'); rc := utl_tcp.write_line(c, 'Content-Disposition: attachment;'); ----- INDICATES THAT THIS IS AN ATTACHMENT rc := utl_tcp.write_line(c, ' filename="Test.txt"'); ----- SUGGESTED FILE NAME FOR ATTACHMENT rc := utl_tcp.write_line(c, ); rc := utl_tcp.write_line(c, v_output1); rc := utl_tcp.write_line(c, '-------SECBOUND--'); rc := utl_tcp.write_line(c, ); rc := utl_tcp.write_line(c, '.'); ----- EMAIL MESSAGE BODY END dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'QUIT'); ----- ENDS EMAIL TRANSACTION dbms_output.put_line(utl_tcp.get_line(c, TRUE)); utl_tcp.close_connection(c); ----- CLOSE SMTP PORT CONNECTIONEXCEPTION when others then raise_application_error(-20000, SQLERRM);END;/

Send multiple E-mails with or without attachment Package.

Send E-mail messages with or without attachment from PL/SQL using UTL_TCP:

Use CLOB for no limit on attachment text size. Multiple E-mail addresses must be separated by commas. Do not add comma for single address or at the end of multiple address string; even if you do, it still works. These procedures add a comma at the end of the E-mail string.

CSV Files require CHR(10) at the end of each line. TEXT Files require CHR(13)||CHR(10) at the end of each line.create or replace Package SEND_EMAIL_FROM_PL_SQL IS procedure send_email_with_attachment ( sender_email_address varchar2, -- Must be single E-mail address recipient_email_addresses varchar2, email_subject varchar2, email_body_text varchar2, email_attachment_text clob, -- No restriction on size of text email_attachment_file_name varchar2 );procedure send_email_without_attachment

www.saturninfotech.com

Page 28: Pl SQL Document by Mv

PL SQL Document 28

( sender_email_address varchar2, -- Must be single E-mail address recipient_email_addresses varchar2, email_subject varchar2, email_body_text varchar2 );END; ---- of Specification for Package SEND_EMAIL_FROM_PL_SQL/show errorscreate or replace Package Body SEND_EMAIL_FROM_PL_SQL ISprocedure send_email_with_attachment ( sender_email_address varchar2, -- Must be single E-mail address recipient_email_addresses varchar2, email_subject varchar2, email_body_text varchar2, email_attachment_text clob, -- No restriction on size of text email_attachment_file_name varchar2 ) IS c utl_tcp.connection; rc binary_integer; v_next_column binary_integer; v_recipient_email_length binary_integer; v_recipient_email_addresses varchar2 (500); v_single_recipient_email_addr varchar2 (100); -- Variables to divide the CLOB into 32000 character segments to write to the file j binary_integer; current_position binary_integer :=1; email_attachment_text_segment clob :=; BEGIN v_recipient_email_addresses := recipient_email_addresses; v_recipient_email_length  := length(v_recipient_email_addresses); v_recipient_email_addresses := v_recipient_email_addresses||','; -- Add comma for the last asddress v_next_column  := 1; if instr(v_recipient_email_addresses, ',') = 0 then -- Single E-mail address v_single_recipient_email_addr := v_recipient_email_addresses; v_recipient_email_length := 1; end if; -- Open the SMTP port 25 on UWA mailhost local machine c := utl_tcp.open_connection('mailhost.yourcompany.com', 25); -- Performs handshaking with the SMTP Server. HELO is the correct spelling. -- DO NOT CHANGE. Causes problems. rc := utl_tcp.write_line(c, 'HELO localhost'); dbms_output.put_line(utl_tcp.get_line(c, TRUE)); while v_next_column <= v_recipient_email_length loop -- Process Multiple E-mail addresses in the loop OR single E-mail address once. v_single_recipient_email_addr  := substr( v_recipient_email_addresses, v_next_column,

www.saturninfotech.com

Page 29: Pl SQL Document by Mv

PL SQL Document 29

instr(v_recipient_email_addresses, ',',v_next_column) -v_next_column ); v_next_column := instr(v_recipient_email_addresses,',',v_next_column)+1; rc := utl_tcp.write_line(c, 'MAIL FROM: '||sender_email_address); -- MAIL BOX SENDING THE EMAIL dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'RCPT TO: '||v_single_recipient_email_addr);

-- MAIL BOX RECIEVING THE EMAIL dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'DATA'); -- START EMAIL MESSAGE BODY dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'Date: '||TO_CHAR( SYSDATE, 'dd Mon yy hh24:mi:ss' )); rc := utl_tcp.write_line(c, 'From: '||sender_email_address); rc := utl_tcp.write_line(c, 'MIME-Version: 1.0'); rc := utl_tcp.write_line(c, 'To: '||v_single_recipient_email_addr); rc := utl_tcp.write_line(c, 'Subject: '||email_subject); rc := utl_tcp.write_line(c, 'Content-Type: multipart/mixed;'); -- INDICATES THAT THE BODY CONSISTS OF MORE THAN ONE PART rc := utl_tcp.write_line(c, ' boundary="-----SECBOUND"'); -- SEPERATOR USED TO SEPERATE THE BODY PARTS rc := utl_tcp.write_line(c, ); -- DO NOT REMOVE THIS BLANK LINE - MIME STANDARD rc := utl_tcp.write_line(c, '-------SECBOUND'); rc := utl_tcp.write_line(c, 'Content-Type: text/plain'); -- 1ST BODY PART. EMAIL TEXT MESSAGE rc := utl_tcp.write_line(c, 'Content-Transfer-Encoding: 7bit'); rc := utl_tcp.write_line(c, ); rc := utl_tcp.write_line(c, email_body_text); -- TEXT OF EMAIL MESSAGE rc := utl_tcp.write_line(c, ); rc := utl_tcp.write_line(c, '-------SECBOUND'); rc := utl_tcp.write_line(c, 'Content-Type: text/plain;'); -- 2ND BODY PART. rc := utl_tcp.write_line(c, ' name="' ||email_attachment_file_name || '"'); rc := utl_tcp.write_line(c, 'Content-Transfer_Encoding: 8bit'); rc := utl_tcp.write_line(c, 'Content-Disposition: attachment;');-- INDICATES THAT THIS IS AN ATTACHMENT rc := utl_tcp.write_line(c, ); -- Divide the CLOB into 32000 character segments to write to the file. -- Even though SUBSTR looks for 32000 characters, UTL_TCP.WRITE_LINE does not blank pad it. current_position := 1; j  := (round(length(email_attachment_text))/32000) + 1; dbms_output.put_line('j= '||j||' length= '||length(email_attachment_text)); for i in 1..j loop email_attachment_text_segment := substr(email_attachment_text, current_position, 32000); rc := utl_tcp.write_line(c, email_attachment_text_segment); current_position := current_position + 32000; end loop;

www.saturninfotech.com

Page 30: Pl SQL Document by Mv

PL SQL Document 30

rc := utl_tcp.write_line(c, '-------SECBOUND--'); rc := utl_tcp.write_line(c, ); rc := utl_tcp.write_line(c, '.'); -- END EMAIL MESSAGE BODY dbms_output.put_line(utl_tcp.get_line(c, TRUE)); dbms_output.put_line('***** Single E-mail= '||v_single_recipient_email_addr||' '||v_next_column); end loop; rc := utl_tcp.write_line(c, 'QUIT'); -- ENDS EMAIL TRANSACTION dbms_output.put_line(utl_tcp.get_line(c, TRUE)); utl_tcp.close_connection(c); -- CLOSE SMTP PORT CONNECTIONEND; -- of Procedure SEND_EMAIL_WITH_ATTACHMENTprocedure send_email_without_attachment ( sender_email_address varchar2, -- Must be single E-mail address recipient_email_addresses varchar2, email_subject varchar2, email_body_text varchar2 ) IS c utl_tcp.connection; rc binary_integer; v_next_column binary_integer; v_recipient_email_length binary_integer; v_recipient_email_addresses varchar2 (500); v_single_recipient_email_addr varchar2 (100); BEGIN v_recipient_email_addresses := recipient_email_addresses; v_recipient_email_length  := length(v_recipient_email_addresses); v_recipient_email_addresses := v_recipient_email_addresses||','; --Add comma for the last asddress v_next_column  := 1; if instr(v_recipient_email_addresses, ',') = 0 then -- Single E-mail address v_single_recipient_email_addr := v_recipient_email_addresses; v_recipient_email_length := 1; end if; -- open the SMTP port 25 on UWA mailhost local machine c := utl_tcp.open_connection('mailhost.yourcompany.com', 25); dbms_output.put_line(utl_tcp.get_line(c, TRUE)); -- Performs handshaking with the SMTP Server. HELO is the correct spelling. -- DO NOT CHANGE. Causes problems. rc := utl_tcp.write_line(c, 'HELO localhost'); dbms_output.put_line(utl_tcp.get_line(c, TRUE)); while v_next_column <= v_recipient_email_length loop -- Process Multiple E-mail addresses in the loop or single E-mail address once. v_single_recipient_email_addr  := substr( v_recipient_email_addresses, v_next_column, instr(v_recipient_email_addresses, ',',v_next_column) -v_next_column ); v_next_column := instr(v_recipient_email_addresses,',',v_next_column)+1;

www.saturninfotech.com

Page 31: Pl SQL Document by Mv

PL SQL Document 31

rc := utl_tcp.write_line(c, 'MAIL FROM: '||sender_email_address); dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'RCPT TO: '||v_single_recipient_email_addr); dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'DATA'); -- Start E-mail message body dbms_output.put_line(utl_tcp.get_line(c, TRUE)); rc := utl_tcp.write_line(c, 'Date: '||TO_CHAR( SYSDATE, 'dd Mon yy hh24:mi:ss' )); rc := utl_tcp.write_line(c, 'From: '||sender_email_address); rc := utl_tcp.write_line(c, 'MIME-Version: 1.0'); rc := utl_tcp.write_line(c, 'To: '||v_single_recipient_email_addr); rc := utl_tcp.write_line(c, 'Subject: '||email_subject); rc := utl_tcp.write_line(c, email_body_text); rc := utl_tcp.write_line(c, '.'); -- End of E-mail message body dbms_output.put_line(utl_tcp.get_line(c, TRUE)); dbms_output.put_line('***** Single E-mail= '||v_single_recipient_email_addr||' '||v_next_column); end loop; rc := utl_tcp.write_line(c, 'QUIT'); -- End E-mail transaction dbms_output.put_line(utl_tcp.get_line(c, TRUE)); utl_tcp.close_connection(c); -- Close the connectionEND; -- of Procedure SEND_EMAIL_WITHOUT_ATTACHMENT

END; -- of Specification for Package SEND_EMAIL_FROM_PL_SQL/show errorscreate public synonym SEND_EMAIL_FROM_PL_SQL for SEND_EMAIL_FROM_PL_SQL;

www.saturninfotech.com

Page 32: Pl SQL Document by Mv

PL SQL Document 32

UTL_SMTP

The UTL_SMTP package is designed for sending electronic mails (emails) over Simple Mail Transfer Protocol (SMTP) as specified by RFC821.

See Also:

How to use the SMTP package to send email in Oracle Database Application Developer's Guide - Fundamentals

This chapter contains the following topics:

Using UTL_SMTP o Overviewo Typeso Reply Codeso Exceptionso Rules and Limitso Examples

Summary of UTL_SMTP Subprograms

Using UTL_SMTP

Overview Types Reply Codes Exceptions Rules and Limits Examples

Overview

The protocol consists of a set of commands for an email client to dispatch emails to a SMTP server. The UTL_SMTP package provides interfaces to the SMTP commands. For many of the commands, the package provides both a procedural and a functional interface. The functional form returns the reply from the server for processing by the client. The procedural form checks the reply and will raise an exception if the reply indicates a transient (400-range reply code) or permanent error (500-range reply code). Otherwise, it discards the reply.

www.saturninfotech.com

Page 33: Pl SQL Document by Mv

PL SQL Document 33

Note that the original SMTP protocol communicates using 7-bit ASCII. Using UTL_SMTP, all text data (in other words, those in VARCHAR2) will be converted to US7ASCII before it is sent over the wire to the server. Some implementations of SMTP servers that support SMTP extension 8BITMIME [RFC1652] support full 8-bit communication between client and server. The body of the DATA command may be transferred in full 8 bits, but the rest of the SMTP command and response should be in 7 bits. When the target SMTP server supports 8BITMIME extension, users of multibyte databases may convert their non-US7ASCII, multibyte VARCHAR2 data to RAW and use the WRITE_RAW_DATA subprogram to send multibyte data using 8-bit MIME encoding.

UTL_SMTP provides for SMTP communication as specified in RFC821, but does not provide an API to format the content of the message according to RFC 822 (for example, setting the subject of an electronic mail).You must format the message appropriately. In addition, UTL_SMTP does not have the functionality to implement an SMTP server for an email clients to send emails using SMTP.

Note :

RFC documents are "Request for Comments" documents that describe proposed standards for public review on the Internet. For the actual RFC documents, please refer to:

http://www.ietf.org/rfc/

Types

CONNECTION Record Type REPLY, REPLIES Record Types

CONNECTION Record Type

This is a PL/SQL record type used to represent an SMTP connection.

Syntax

TYPE connection IS RECORD ( host VARCHAR2(255), -- remote host name port PLS_INTEGER, -- remote port number tx_timeout PLS_INTEGER, -- Transfer time out (in seconds) private_tcp_con utl_tcp.connection, -- private, for implementation use private_state PLS_INTEGER -- private, for implementation use);

Fields

www.saturninfotech.com

Page 34: Pl SQL Document by Mv

PL SQL Document 34

Table 178-1 CONNECTION Record Type Fields

Field Description

host The name of the remote host when connection is established. NULL when no connection is established.

port The port number of the remote SMTP server connected. NULL when no connection is established.

tx_timeout The time in seconds that the UTL_SMTP package waits before giving up in a read or write operation in this connection. In read operations, this package gives up if no data is available for reading immediately. In write operations, this package gives up if the output buffer is full and no data is to be sent into the network without being blocked. 0 indicates not to wait at all. NULL indicates to wait forever.

private_tcp_con Private, for implementation use only. You should not modify this field.

private_state Private, for implementation use only. You should not modify this field.

Usage Notes

The read-only fields in a connection record are used to return information about the SMTP connection after the connection is successfully made with open_connection(). Changing the values of these fields has no effect on the connection. The fields private_xxx are for implementation use only. You should not modify these fields.

REPLY, REPLIES Record Types

These are PL/SQL record types used to represent an SMTP reply line. Each SMTP reply line consists of a reply code followed by a text message. While a single reply line is expected for most SMTP commands, some SMTP commands expect multiple reply lines. For those situations, a PL/SQL table of reply records is used to represent multiple reply lines.

Syntax

TYPE reply IS RECORD ( code PLS_INTEGER, -- 3-digit reply code text VARCHAR2(508) -- text message);TYPE replies IS TABLE OF reply INDEX BY BINARY_INTEGER; -- multiple reply lines

Fields

Table 178-2 REPLY, REPLIES Record Type Fields

www.saturninfotech.com

Page 35: Pl SQL Document by Mv

PL SQL Document 35

Field Description

code The 3-digit reply code.

text The text message of the reply.

Reply Codes

The following is a list of the SMTP reply codes.

Table 178-3 SMTP Reply Codes

Reply Code Meaning

211 System status, or system help reply

214 Help message [Information on how to use the receiver or the meaning of a particular non-standard command; this reply is useful only to the human user]

220 <domain> Service ready

221 <domain> Service closing transmission channel

250 Requested mail action okay, completed

251 User not local; will forward to <forward-path>

252 OK, pending messages for node <node> started. Cannot VRFY user (for example, info is not local), but will take message for this user and attempt delivery.

253 OK, <messages> pending messages for node <node> started

354 Start mail input; end with <CRLF>.<CRLF>

355 Octet-offset is the transaction offset

421 <domain> Service not available, closing transmission channel (This may be a reply to any command if the service knows it must shut down.)

450 Requested mail action not taken: mailbox unavailable [for example, mailbox busy]

451 Requested action terminated: local error in processing

452 Requested action not taken: insufficient system storage

453 You have no mail.

454 TLS not available due to temporary reason. Encryption required for requested authentication mechanism.

www.saturninfotech.com

Page 36: Pl SQL Document by Mv

PL SQL Document 36

Reply Code Meaning

458 Unable to queue messages for node <node>

459 Node <node> not allowed: reason

500 Syntax error, command unrecognized (This may include errors such as command line too long.)

501 Syntax error in parameters or arguments

502 Command not implemented

503 Bad sequence of commands

504 Command parameter not implemented

521 <Machine> does not accept mail.

530 Must issue a STARTTLS command first. Encryption required for requested authentication mechanism.

534 Authentication mechanism is too weak.

538 Encryption required for requested authentication mechanism.

550 Requested action not taken: mailbox unavailable [for , mailbox not found, no access]

551 User not local; please try <forward-path>

552 Requested mail action terminated: exceeded storage allocation

553 Requested action not taken: mailbox name not allowed [for example, mailbox syntax incorrect]

554 Transaction failed

Exceptions

The table lists the exceptions that can be raised by the interface of the UTL_SMTP package. The network error is transferred to a reply code of 421- service not available.

Table 178-4 UTL_SMTP Exceptions

INVALID_OPERATION Raised when an invalid operation is made. In other words, calling API other than write_data(), write_raw_data() or close_data() after open_data() is called, or calling write_data(), write_raw_data() or close_data() without first calling open_data().

www.saturninfotech.com

Page 37: Pl SQL Document by Mv

PL SQL Document 37

TRANSIENT_ERROR Raised when receiving a reply code in 400 range.

PERMANENT_ERROR Raised when receiving a reply code in 500 range.

Rules and Limits

No limitation or range-checking is imposed by the API. However, you should be aware of the following size limitations on various elements of SMTP. Sending data that exceed these limits may result in errors returned by the server.

Table 178-5 SMTP Size Limitation

Element Size Limitation

user The maximum total length of a user name is 64 characters.

domain The maximum total length of a domain name or number is 64 characters.

path The maximum total length of a reverse-path or forward-path is 256 characters (including the punctuation and element separators).

command line The maximum total length of a command line including the command word and the <CRLF> is 512 characters.

reply line The maximum total length of a reply line including the reply code and the <CRLF> is 512 characters.

text line The maximum total length of a text line including the <CRLF> is 1000 characters (but not counting the leading dot duplicated for transparency).

recipients buffer

The maximum total number of recipients that must be buffered is 100 recipients.

Examples

The following example illustrates how UTL_SMTP is used by an application to send e-mail. The application connects to an SMTP server at port 25 and sends a simple text message.

DECLARE c UTL_SMTP.CONNECTION; PROCEDURE send_header(name IN VARCHAR2, header IN VARCHAR2) AS BEGIN

www.saturninfotech.com

Page 38: Pl SQL Document by Mv

PL SQL Document 38

UTL_SMTP.WRITE_DATA(c, name || ': ' || header || UTL_TCP.CRLF); END; BEGIN c := UTL_SMTP.OPEN_CONNECTION('smtp-server.acme.com'); UTL_SMTP.HELO(c, 'foo.com'); UTL_SMTP.MAIL(c, '[email protected]'); UTL_SMTP.RCPT(c, '[email protected]'); UTL_SMTP.OPEN_DATA(c); send_header('From', '"Sender" <[email protected]>'); send_header('To', '"Recipient" <[email protected]>'); send_header('Subject', 'Hello'); UTL_SMTP.WRITE_DATA(c, UTL_TCP.CRLF || 'Hello, world!'); UTL_SMTP.CLOSE_DATA(c); UTL_SMTP.QUIT(c);EXCEPTION WHEN utl_smtp.transient_error OR utl_smtp.permanent_error THEN BEGIN UTL_SMTP.QUIT(c); EXCEPTION WHEN UTL_SMTP.TRANSIENT_ERROR OR UTL_SMTP.PERMANENT_ERROR THEN NULL; -- When the SMTP server is down or unavailable, we don't have -- a connection to the server. The QUIT call will raise an -- exception that we can ignore. END; raise_application_error(-20000, 'Failed to send mail due to the following error: ' || sqlerrm);END;

Summary of UTL_SMTP Subprograms

UTL_SMTP Package Subprograms

Subprogram Description

CLOSE_DATA Function and Procedure

Closes the data session

COMMAND Function and Procedure

Performs a generic SMTP command

COMMAND_REPLIES Function

Performs initial handshaking with SMTP server after connecting

DATA Function and Procedure Performs initial handshaking with SMTP server after connecting, with extended information returned

EHLO Function and Procedure Performs initial handshaking with SMTP server after connecting, with extended information returned

HELO Function and Procedure Performs initial handshaking with SMTP server after

www.saturninfotech.com

Page 39: Pl SQL Document by Mv

PL SQL Document 39

Subprogram Description

connecting

HELP Function Sends HELP command

MAIL Function and Procedure Initiates a mail transaction with the server, the destination is a mailbox

NOOP Function and Procedure The null command

OPEN_CONNECTION Functions

Opens a connection to an SMTP server

OPEN_DATA Function and Procedure

Sends the DATA command

QUIT Function and Procedure Terminates an SMTP session and disconnects from the server

RCPT Function Specifies the recipient of an e-mail message

RSET Function and Procedure Terminates the current mail transaction

VRFY Function Verifies the validity of a destination e-mail address

WRITE_DATA Procedure Writes a portion of the e-mail message

WRITE_RAW_DATA Procedure

Writes a portion of the e-mail message with RAW data

CLOSE_DATA Function and Procedure

The CLOSE_DATA call ends the e-mail message by sending the sequence <CR><LF>.<CR><LF> (a single period at the beginning of a line).

Syntax

UTL_SMTP.CLOSE_DATA ( c IN OUT NOCOPY connection) RETURN reply;

UTL_SMTP.CLOSE_DATA ( c IN OUT NOCOPY connection);

Parameters

Table 178-7 CLOSE_DATA Function and Procedure Parameters

www.saturninfotech.com

Page 40: Pl SQL Document by Mv

PL SQL Document 40

Parameter Description

c The SMTP connection.

Return Values

Table 178-8 CLOSE_DATA Function and Procedure Return Values

Return Value Description

reply Reply of the command (see REPLY, REPLIES Record Types). In cases where there are multiple replies, the last reply will be returned.

Usage Notes

The calls to OPEN_DATA, WRITE_DATA, WRITE_RAW_DATA and CLOSE_DATA must be made in the right order. A program calls OPEN_DATA to send the DATA command to the SMTP server. After that, it can call WRITE_DATA or WRITE_RAW_DATA repeatedly to send the actual data. The data is terminated by calling CLOSE_DATA. After OPEN_DATA is called, the only subprograms that can be called are WRITE_DATA, WRITE_RAW_DATA, or CLOSE_DATA. A call to other APIs will result in an INVALID_OPERATION exception being raised.

CLOSE_DATA should be called only after OPEN_CONNECTION, HELO or EHLO, MAIL, and RCPT have been called. The connection to the SMTP server must be open and a mail transaction must be active when this routine is called.

Note that there is no function form of WRITE_DATA because the SMTP server does not respond until the data-terminator is sent during the call to CLOSE_DATA.

COMMAND Function and Procedure

This function/procedure performs a generic SMTP command.

Syntax

UTL_SMTP.COMMAND ( c IN OUT NOCOPY connection, cmd IN VARCHAR2, arg IN VARCHAR2 DEFAULT NULL)

www.saturninfotech.com

Page 41: Pl SQL Document by Mv

PL SQL Document 41

RETURN reply;

UTL_SMTP.COMMAND ( c IN OUT NOCOPY connection, cmd IN VARCHAR2, arg IN VARCHAR2 DEFAULT NULL);

Parameters

Table 178-9 COMMAND Function and Procedure Parameters

Parameter Description

c The SMTP connection.

cmd The SMTP command to send to the server.

arg The optional argument to the SMTP argument. A space will be inserted between cmd and arg.

Return Values

Table 178-10 COMMAND Function and Procedure Return Values

Return Value Description

reply Reply of the command (see REPLY, REPLIES Record Types). In cases where there are multiple replies, the last reply will be returned.

Usage Notes

This function is used to invoke generic SMTP commands. Use COMMAND if only a single reply line is expected. Use COMMAND_REPLIES if multiple reply lines are expected.

For COMMAND, if multiple reply lines are returned from the SMTP server, it returns the last reply line only.

COMMAND_REPLIES Function

This functions performs a generic SMTP command.

www.saturninfotech.com

Page 42: Pl SQL Document by Mv

PL SQL Document 42

Syntax

UTL_SMTP.COMMAND_REPLIES ( c IN OUT NOCOPY connection, cmd IN VARCHAR2, arg IN VARCHAR2 DEFAULT NULL)RETURN replies;

Parameters

Table 178-11 COMMAND_REPLIES Function Parameters

Parameter Description

c The SMTP connection.

cmd The SMTP command to send to the server.

arg The optional argument to the SMTP argument. A space will be inserted between cmd and arg.

Return Values

Table 178-12 COMMAND_REPLIES Function Return Values

Return Value Description

replies Reply of the command (see REPLY, REPLIES Record Types).

Usage Notes

This function is used to invoke generic SMTP commands. Use COMMAND if only a single reply line is expected. Use COMMAND_REPLIES if multiple reply lines are expected.

For COMMAND, if multiple reply lines are returned from the SMTP server, it returns the last reply line only.

DATA Function and Procedure

This function/procedure specifies the body of an e-mail message.

www.saturninfotech.com

Page 43: Pl SQL Document by Mv

PL SQL Document 43

Syntax

UTL_SMTP.DATA ( c IN OUT NOCOPY connection body IN VARCHAR2 CHARACTER SET ANY_CS) RETURN reply;

UTL_SMTP.DATA ( c IN OUT NOCOPY connection body IN VARCHAR2 CHARACTER SET ANY_CS);

Parameters

Table 178-13 DATA Function and Procedure Parameters

Parameter Description

c The SMTP Connection.

body The text of the message to be sent, including headers, in [RFC822] format.

Return Values

Table 178-14 DATA Function and Procedure Return Values

Return Value Description

reply Reply of the command (see REPLY, REPLIES Record Types). In cases where there are multiple replies, the last reply will be returned.

Usage Notes

The application must ensure that the contents of the body parameter conform to the MIME(RFC822) specification. The DATA routine will terminate the message with a <CR><LF>.<CR><LF> sequence (a single period at the beginning of a line), as required by RFC821. It will also translate any sequence of <CR><LF>.<CR><LF> (single period) in body to <CR><LF>..<CR><LF> (double period). This conversion provides the transparency as described in Section 4.5.2 of RFC821.

The DATA call should be called only after OPEN_CONNECTION, HELO or EHLO, MAIL and RCPT have been called. The connection to the SMTP server must be open, and a mail transaction must be active when this routine is called.

www.saturninfotech.com

Page 44: Pl SQL Document by Mv

PL SQL Document 44

The expected response from the server is a message beginning with status code 250. The 354 response received from the initial DATA command will not be returned to the caller.

EHLO Function and Procedure

This function/procedure performs initial handshaking with SMTP server after connecting, with extended information returned.

Syntax

UTL_SMTP.EHLO ( c IN OUT NOCOPY connection, domain IN) RETURN replies;

UTL_SMTP.EHLO ( c IN OUT NOCOPY connection, domain IN);

Parameters

Table 178-15 EHLO Function and Procedure Parameters

Parameter Description

c The SMTP connection.

domain The domain name of the local (sending) host. Used for identification purposes.

Return Values

Table 178-16 EHLO Function and Procedure Return Values

Return Value Description

replies Reply of the command (see REPLY, REPLIES Record Types).

Usage Notes

The EHLO interface is identical to HELO except that it allows the server to return more descriptive information about its configuration. [RFC1869] specifies the format of the information returned,

www.saturninfotech.com

Page 45: Pl SQL Document by Mv

PL SQL Document 45

which the PL/SQL application can retrieve using the functional form of this call. For compatibility with HELO, each line of text returned by the server begins with status code 250.

Related Functions

HELO

HELO Function and Procedure

This function/procedure performs initial handshaking with SMTP server after connecting.

Syntax

UTL_SMTP.HELO ( c IN OUT NOCOPY connection, domain IN VARCHAR2) RETURN reply;

UTL_SMTP.HELO ( c IN OUT NOCOPY connection, domain IN VARCHAR2);

Parameters

Table 178-17 HELO Function and Procedure Parameters

Parameter Description

c The SMTP connection.

domain The domain name of the local (sending) host. Used for identification purposes.

Return Values

Table 178-18 HELO Function and Procedure Return Values

Return Value Description

reply Reply of the command (see REPLY, REPLIES Record Types). In cases where there are multiple replies, the last reply will be returned.

www.saturninfotech.com

Page 46: Pl SQL Document by Mv

PL SQL Document 46

Usage Notes

RFC 821 specifies that the client must identify itself to the server after connecting. This routine performs that identification. The connection must have been opened through a call to OPEN_CONNECTION Functions before calling this routine.

The expected response from the server is a message beginning with status code 250.

Related Functions

EHLO

HELP Function

This function sends the HELP command.

Syntax

UTL_SMTP.HELP ( c IN OUT NOCOPY connection, command IN VARCHAR2 DEFAULT NULL) RETURN replies;

Parameters

Table 178-19 HELP Function Parameters

Parameter Description

c The SMTP connection.

command The command to get the help message.

Return Values

Table 178-20 HELP Function Return Values

Return Value Description

replies Reply of the command (see REPLY, REPLIES Record Types).

www.saturninfotech.com

Page 47: Pl SQL Document by Mv

PL SQL Document 47

MAIL Function and Procedure

This function/procedure initiates a mail transaction with the server. The destination is a mailbox.

Syntax

UTL_SMTP.MAIL ( c IN OUT NOCOPY connection, sender IN VARCHAR2, parameters IN VARCHAR2 DEFAULT NULL) RETURN reply;

UTL_SMTP.MAIL ( c IN OUT NOCOPY connection, sender IN VARCHAR2, parameters IN VARCHAR2 DEFAULT NULL);

Parameters

Table 178-21 MAIL Function and Procedure Parameters

Parameter Description

c The SMTP connection.

sender The e-mail address of the user sending the message.

parameters The additional parameters to MAIL command as defined in Section 6 of [RFC1869]. It should follow the format of "XXX=XXX (XXX=XXX ....)".

Return Values

Table 178-22 MAIL Function and Procedure Return Values

Return Value Description

reply Reply of the command (see REPLY, REPLIES Record Types). In cases where there are multiple replies, the last reply will be returned.

Usage Notes

www.saturninfotech.com

Page 48: Pl SQL Document by Mv

PL SQL Document 48

This command does not send the message; it simply begins its preparation. It must be followed by calls to RCPT and DATA to complete the transaction. The connection to the SMTP server must be open and a HELO or EHLO command must have already been sent.

The expected response from the server is a message beginning with status code 250.

NOOP Function and Procedure

The null command.

Syntax

UTL_SMTP.NOOP ( c IN OUT NOCOPY connection) RETURN reply;

UTL_SMTP.NOOP ( c IN OUT NOCOPY connection);

Parameter

Table 178-23 NOOP Function and Procedure Parameters

Parameter Description

c The SMTP connection.

Return Values

Table 178-24 NOOP Function and Procedure Return Values

Return Value Description

reply Reply of the command (see REPLY, REPLIES Record Types). In cases where there are multiple replies, the last reply will be returned.

Usage Notes

www.saturninfotech.com

Page 49: Pl SQL Document by Mv

PL SQL Document 49

This command has no effect except to elicit a successful reply from the server. It can be issued at any time after the connection to the server has been established with OPEN_CONNECTION. The NOOP command can be used to verify that the server is still connected and is listening properly.

This command will always reply with a single line beginning with status code 250.

OPEN_CONNECTION Functions

These functions open a connection to an SMTP server.

Syntax

UTL_SMTP.OPEN_CONNECTION ( host IN VARCHAR2, port IN PLS_INTEGER DEFAULT 25, c OUT connection, tx_timeout IN PLS_INTEGER DEFAULT NULL) RETURN reply;

UTL_SMTP.OPEN_CONNECTION ( host IN VARCHAR2, port IN PLS_INTEGER DEFAULT 25, tx_timeout IN PLS_INTEGER DEFAULT NULL) RETURN connection;

Parameters

Table 178-25 OPEN_CONNECTION Functions Parameters

Parameter Description

host The name of the SMTP server host

port The port number on which SMTP server is listening (usually 25).

c The SMTP connection.

tx_timeout The time in seconds that the UTL_SMTP package waits before giving up in a read or write operation in this connection. In read operations, this package gives up if no data is available for reading immediately. In write operations, this package gives up if the output buffer is full and no data is to be sent into the network without being blocked. 0 indicates not to wait at all. NULL indicates to wait forever.

Return Values

www.saturninfotech.com

Page 50: Pl SQL Document by Mv

PL SQL Document 50

Table 178-26 OPEN_CONNECTION Functions Return Values

Return Value Description

reply Reply of the command (see REPLY, REPLIES Record Types). In cases where there are multiple replies, the last reply will be returned.

Usage Notes

The expected response from the server is a message beginning with status code 220. The version of OPEN_CONNECTION that returns UTL_SMTP.CONNECTION record checks the

reply code returned by an SMTP server when the connection is first established. It raises an exception when the reply indicates an error. Otherwise, it discards the reply. If a user is interested in examining the reply, he or she can invoke the version of OPEN_CONNECTION that returns REPLY.

A timeout on the WRITE operations feature is not supported in the current release of this package.

OPEN_DATA Function and Procedure

OPEN_DATA sends the DATA command after which you can use WRITE_DATA and WRITE_RAW_DATA to write a portion of the e-mail message.

Syntax

UTL_SMTP.OPEN_DATA ( c IN OUT NOCOPY connection) RETURN reply;

UTL_SMTP.OPEN_DATA ( c IN OUT NOCOPY connection);

Parameters

Table 178-27 OPEN_DATA Function and Procedure Parameters

Parameter Description

c The SMTP connection.

data The portion of the text of the message to be sent, including headers, in [RFC822]

www.saturninfotech.com

Page 51: Pl SQL Document by Mv

PL SQL Document 51

Parameter Description

format.

Return Values

Table 178-28 OPEN_DATA Function and Procedure Function Return Values

Return Value Description

reply Reply of the command (see REPLY, REPLIES Record Types). In cases where there are multiple replies, the last reply will be returned.

Usage Notes

The calls to OPEN_DATA, WRITE_DATA, WRITE_RAW_DATA and CLOSE_DATA must be made in the right order. A program calls OPEN_DATA to send the DATA command to the SMTP server. After that, it can call WRITE_DATA or WRITE_RAW_DATA repeatedly to send the actual data. The data is terminated by calling CLOSE_DATA. After OPEN_DATA is called, the only subprograms that can be called are WRITE_DATA, WRITE_RAW_DATA, or CLOSE_DATA. A call to other APIs will result in an INVALID_OPERATION exception being raised.

OPEN_DATA should be called only after OPEN_CONNECTION, HELO or EHLO, MAIL, and RCPT have been called. The connection to the SMTP server must be open and a mail transaction must be active when this routine is called.

QUIT Function and Procedure

This function terminates an SMTP session and disconnects from the server.

Syntax

UTL_SMTP.QUIT ( c IN OUT NOCOPY connection) RETURN reply;

UTL_SMTP.QUIT ( c IN OUT NOCOPY connection);

www.saturninfotech.com

Page 52: Pl SQL Document by Mv

PL SQL Document 52

Parameter

Table 178-29 QUIT Function and Procedure Parameters

Parameter Description

c The SMTP connection.

Return Values

Table 178-30 QUIT Function and Procedure Function Return Values

Return Value Description

reply Reply of the command (see REPLY, REPLIES Record Types). In cases where there are multiple replies, the last reply will be returned.

Usage Notes

The QUIT command informs the SMTP server of the client's intent to terminate the session. It then closes the connection established by OPEN_CONNECTION which must have been called before executing this command. If a mail transaction is in progress when QUIT is issued, it is abandoned in the same manner as RSET.

The function form of this command returns a single line beginning with the status code 221 on successful termination. In all cases, the connection to the SMTP server is closed. The fields REMOTE_HOST and REMOTE_PORT of c are reset.

Related Functions

RSET

RCPT Function

This function/procedure specifies the recipient of an e-mail message.

Syntax

www.saturninfotech.com

Page 53: Pl SQL Document by Mv

PL SQL Document 53

UTL_SMTP.RCPT ( c IN OUT NOCOPY connection, recipient IN VARCHAR2, parameters IN VARCHAR2 DEFAULT NULL)RETURN reply;

UTL_SMTP.RCPT ( c IN OUT NOCOPY connection, recipient IN VARCHAR2, parameters IN VARCHAR2 DEFAULT NULL);

Table 178-31 RCPT Function and Procedure Parameters

Parameter Description

c The SMTP connection.

recipient The e-mail address of the user to which the message is being sent.

parameters The additional parameters to RCPT command as defined in Section 6 of [RFC1869]. It should follow the format of "XXX=XXX (XXX=XXX ....)".

Return Values

Table 178-32 RCPT Function and Procedure Function Return Values

Return Value Description

reply Reply of the command (see REPLY, REPLIES Record Types). In cases where there are multiple replies, the last reply will be returned.

Usage Notes

To send a message to multiple recipients, call this routine multiple times. Each invocation schedules delivery to a single e-mail address. The message transaction must have been begun by a prior call to MAIL, and the connection to the mail server must have been opened and initialized by prior calls to OPEN_CONNECTION and HELO or EHLO respectively.

The expected response from the server is a message beginning with status code 250 or 251.

RSET Function and Procedure

www.saturninfotech.com

Page 54: Pl SQL Document by Mv

PL SQL Document 54

This function terminates the current mail transaction.

Syntax

UTL_SMTP.RSET ( c IN OUT NOCOPY connection) RETURN reply;

UTL_SMTP.RSET ( c IN OUT NOCOPY connection);

Parameters

Table 178-33 RSET Function and Procedure Parameters

Parameter Description

c The SMTP connection.

Return Values

Table 178-34 RSET Function and Procedure Return Values

Return Value Description

reply Reply of the command (see REPLY, REPLIES Record Types). In cases where there are multiple replies, the last reply will be returned.

Usage Notes

This command allows the client to abandon a mail message it was in the process of composing. No mail will be sent. The client can call RSET at any time after the connection to the SMTP server has been opened by means of OPEN_CONNECTION until DATA or OPEN_DATA is called. Once the email data has been sent, it will be too late to prevent the email from being sent.

The server will always respond to RSET with a message beginning with status code 250.

Related Functions

QUIT

www.saturninfotech.com

Page 55: Pl SQL Document by Mv

PL SQL Document 55

VRFY Function

This function verifies the validity of a destination e-mail address.

Syntax

UTL_SMTP.VRFY ( c IN OUT NOCOPY connection recipient IN VARCHAR2) RETURN reply;

Parameters

Table 178-35 VRFY Function Parameters

Parameter Description

c The SMTP connection.

recipient The e-mail address to be verified.

Return Values

Table 178-36 VRFY Function Return Values

Return Value Description

reply Reply of the command (see REPLY, REPLIES Record Types). In cases where there are multiple replies, the last reply will be returned.

Usage Notes

The server attempts to resolve the destination address recipient. If successful, it returns the recipient's full name and fully qualified mailbox path. The connection to the server must have already been established by means of OPEN_CONNECTION and HELO or EHLO before making this request.

Successful verification returns one or more lines beginning with status code 250 or 251.

www.saturninfotech.com

Page 56: Pl SQL Document by Mv

PL SQL Document 56

WRITE_DATA Procedure

Use WRITE_DATA to write a portion of the e-mail message. A repeat call to WRITE_DATA appends data to the e-mail message.

Syntax

UTL_SMTP.WRITE_DATA ( c IN OUT NOCOPY connection, data IN VARCHAR2 CHARACTER SET ANY_CS);

Parameters

Table 178-37 WRITE_DATA Procedure Parameters

Parameter Description

c The SMTP connection.

data The portion of the text of the message to be sent, including headers, in [RFC822] format.

Usage Notes

The calls to OPEN_DATA, WRITE_DATA, WRITE_RAW_DATA and CLOSE_DATA must be made in the right order. A program calls OPEN_DATA to send the DATA command to the SMTP server. After that, it can call WRITE_DATA or WRITE_RAW_DATA repeatedly to send the actual data. The data is terminated by calling CLOSE_DATA. After OPEN_DATA is called, the only subprograms that can be called are WRITE_DATA, WRITE_RAW_DATA, or CLOSE_DATA. A call to other APIs will result in an INVALID_OPERATION exception being raised.

The application must ensure that the contents of the body parameter conform to the MIME(RFC822) specification. The DATA routine will terminate the message with a <CR><LF>.<CR><LF> sequence (a single period at the beginning of a line), as required by RFC821. It will also translate any sequence of <CR><LF>.<CR><LF> (single period) in the body to <CR><LF>..<CR><LF> (double period). This conversion provides the transparency as described in Section 4.5.2 of RFC821.

Notice that this conversion is not bullet-proof. Consider this code fragment:

UTL_SMTP.WRITE_DATA('some message.' || chr(13) || chr(10)); UTL_SMTP.WRITE_DATA('.' || chr(13) || chr(10));

Since the sequence <CR><LF>.<CR><LF> is split between two calls to WRITE_DATA, the implementation of WRITE_DATA will not detect the presence of the data-terminator sequence, and

www.saturninfotech.com

Page 57: Pl SQL Document by Mv

PL SQL Document 57

therefore, will not perform the translation. It will be the responsibility of the user to handle such a situation, or it may result in premature termination of the message data.

WRITE_DATA should be called only after OPEN_CONNECTION, HELO or EHLO, MAIL, and RCPT have been called. The connection to the SMTP server must be open and a mail transaction must be active when this routine is called.

Note that there is no function form of WRITE_DATA because the SMTP server does not respond until the data-terminator is sent during the call to CLOSE_DATA.

Text (VARCHAR2) data sent using WRITE_DATA is converted to US7ASCII before it is sent. If the text contains multibyte characters, each multibyte character in the text that cannot be converted to US7ASCII is replaced by a '?' character. If 8BITMIME extension is negotiated with the SMTP server using the EHLO subprogram, multibyte VARCHAR2 data can be sent by first converting the text to RAW using the UTL_RAW package, and then sending the RAW data using WRITE_RAW_DATA.

WRITE_RAW_DATA Procedure

Use WRITE_RAW_DATA to write a portion of the e-mail message. A repeat call to WRITE_RAW_DATA appends data to the e-mail message.

Syntax

UTL_SMTP.WRITE_RAW_DATA ( c IN OUT NOCOPY connection data IN RAW);

Parameters

Table 178-38 WRITE_RAW_DATA Procedure Parameters

Parameter Description

c The SMTP connection.

data The portion of the text of the message to be sent, including headers, in [RFC822] format.

Usage Notes

The calls to OPEN_DATA, WRITE_DATA, WRITE_RAW_DATA and CLOSE_DATA must be made in the right order. A program calls OPEN_DATA to send the DATA command to the SMTP server. After

www.saturninfotech.com

Page 58: Pl SQL Document by Mv

PL SQL Document 58

that, it can call WRITE_DATA or WRITE_RAW_DATA repeatedly to send the actual data. The data is terminated by calling CLOSE_DATA. After OPEN_DATA is called, the only subprograms that can be called are WRITE_DATA, WRITE_RAW_DATA, or CLOSE_DATA. A call to other APIs will result in an INVALID_OPERATION exception being raised.

The application must ensure that the contents of the body parameter conform to the MIME(RFC822) specification. The DATA routine will terminate the message with a <CR><LF>.<CR><LF> sequence (a single period at the beginning of a line), as required by RFC821. It will also translate any sequence of <CR><LF>.<CR><LF> (single period) in the body to <CR><LF>..<CR><LF> (double period). This conversion provides the transparency as described in Section 4.5.2 of RFC821.

Notice that this conversion is not bullet-proof. Consider this code fragment:

UTL_SMTP.WRITE_DATA('some message.' || chr(13) || chr(10)); UTL_SMTP.WRITE_DATA('.' || chr(13) || chr(10));

Since the sequence <CR><LF>.<CR><LF> is split between two calls to WRITE_DATA, the implementation of WRITE_DATA will not detect the presence of the data-terminator sequence, and therefore, will not perform the translation. It will be the responsibility of the user to handle such a situation, or it may result in premature termination of the message data.

XXX_DATA should be called only after OPEN_CONNECTION, HELO or EHLO, MAIL, and RCPT have been called. The connection to the SMTP server must be open and a mail transaction must be active when this routine is called.

Note that there is no function form of WRITE_DATA because the SMTP server does not respond until the data-terminator is sent during the call to CLOSE_DATA.

Text (VARCHAR2) data sent using WRITE_DATA is converted to US7ASCII before it is sent. If the text contains multibyte characters, each multibyte character in the text that cannot be converted to US7ASCII is replaced by a '?' character. If 8BITMIME extension is negotiated with the SMTP server using the EHLO subprogram, multibyte VARCHAR2 data can be sent by first converting the text to RAW using the UTL_RAW package, and then sending the RAW data using WRITE_RAW_DATA.

www.saturninfotech.com

Page 59: Pl SQL Document by Mv

PL SQL Document 59

UTL_TCP

With the UTL_TCP package and its procedures and functions, PL/SQL applications can communicate with external TCP/IP-based servers using TCP/IP. Because many Internet application protocols are based on TCP/IP, this package is useful to PL/SQL applications that use Internet protocols and e-mail.

This chapter contains the following topics:

Using UTL_TCP o Overviewo Typeso Exceptionso Rules and Limitso Examples

Summary of UTL_TCP Subprograms

Using UTL_TCP

Overview Types Exceptions Rules and Limits Examples

Overview

The UTL_TCP package provides TCP/IP client-side access functionality in PL/SQL.

Types

CONNECTION Type CRLF

CONNECTION Type

This is a PL/SQL record type used to represent a TCP/IP connection.

www.saturninfotech.com

Page 60: Pl SQL Document by Mv

PL SQL Document 60

Syntax

TYPE connection IS RECORD ( remote_host VARCHAR2(255), remote_port PLS_INTEGER, local_host VARCHAR2(255), local_port PLS_INTEGER, charset VARCHAR2(30), newline VARCHAR2(2), tx_timeout PLS_INTEGER, private_sd PLS_INTEGER);

Fields

Table 179-1 Connection Record Type Fields

Field Description

remote_host The name of the remote host when connection is established. NULL when no connection is established.

remote_port The port number of the remote host connected. NULL when no connection is established.

local_host The name of the local host used to establish the connection. NULL when no connection is established.

local_port The port number of the local host used to establish the connection. NULL when no connection is established.

charset The on-the-wire character set. Since text messages in the database may be encoded in a character set that is different from the one expected on the wire (that is, the character set specified by the communication protocol, or the one stipulated by the other end of the communication), text messages in the database will be converted to and from the on-the-wire character set as they are sent and received on the network.

newline The newline character sequence. This newline character sequence is appended to the text line sent by WRITE_LINE API.

tx_timeout A time in seconds that the UTL_TCP package waits before giving up in a read or write operation in this connection. In read operations, this package gives up if no data is available for reading immediately. In write operations, this package gives up if the output buffer is full and no data is to be sent in the network without being blocked. Zero (0) indicates not to wait at all. NULL indicates to wait forever.

Usage Notes

www.saturninfotech.com

Page 61: Pl SQL Document by Mv

PL SQL Document 61

The fields in a connection record are used to return information about the connection, which is often made using OPEN_CONNECTION. Changing the values of those fields has no effect on the connection. The fields private_XXXX are for implementation use only. You should not modify the values.

In the current release of the UTL_TCP package, the parameters local_host and local_port are ignored when open_connection makes a TCP/IP connection. It does not attempt to use the specified local host and port number when the connection is made. The local_host and local_port fields will not be set in the connection record returned by the function.

Time out on write operations is not supported in the current release of the UTL_TCP package.

CRLF

The character sequence carriage-return line-feed. It is the newline sequence commonly used many communication standards.

Syntax

CRLF varchar2(10);

Usage Notes

This package variable defines the newline character sequence commonly used in many Internet protocols. This is the default value of the newline character sequence for WRITE_LINE, specified when a connection is opened. While such protocols use <CR><LF> to denote a new line, some implementations may choose to use just line-feed to denote a new line. In such cases, users can specify a different newline character sequence when a connection is opened.

This CRLF package variable is intended to be a constant that denotes the carriage- return line-feed character sequence. Do not modify its value. Modification may result in errors in other PL/SQL applications.

Exceptions

The exceptions raised by the TCP/IP package are listed in Table 179-2.

Table 179-2 TCP/IP Exceptions

Exception Description

BUFFER_TOO_SMALL Buffer is too small for input that requires look-ahead.

www.saturninfotech.com

Page 62: Pl SQL Document by Mv

PL SQL Document 62

Exception Description

END_OF_INPUT Raised when no more data is available to read from the connection.

NETWORK_ERROR Generic network error.

BAD_ARGUMENT Bad argument passed in an API call (for example, a negative buffer size).

TRANSFER_TIMEOUT No data is read and a read time out occurred.

PARTIAL_MULTIBYTE_CHAR

No complete character is read and a partial multibyte character is found at the end of the input.

Rules and Limits

The interface provided in the package only allows connections to be initiated by the PL/SQL program. It does not allow the PL/SQL program to accept connections initiated outside the program.

Examples

The following code example illustrates how the TCP/IP package can be used to retrieve a Web page over HTTP. It connects to a Web server listening at port 80 (standard port for HTTP) and requests the root document.

DECLARE c utl_tcp.connection; -- TCP/IP connection to the Web server ret_val pls_integer; BEGIN c := utl_tcp.open_connection(remote_host => 'www.acme.com', remote_port => 80, charset => 'US7ASCII'); -- open connection ret_val := utl_tcp.write_line(c, 'GET / HTTP/1.0'); -- send HTTP request ret_val := utl_tcp.write_line(c); BEGIN LOOP dbms_output.put_line(utl_tcp.get_line(c, TRUE)); -- read result END LOOP; EXCEPTION WHEN utl_tcp.end_of_input THEN NULL; -- end of input END; utl_tcp.close_connection(c);END;

www.saturninfotech.com

Page 63: Pl SQL Document by Mv

PL SQL Document 63

The following code example illustrates how the TCP/IP package can be used by an application to send e-mail (also known as email from PL/SQL). The application connects to an SMTP server at port 25 and sends a simple text message.

PROCEDURE send_mail (sender IN VARCHAR2, recipient IN VARCHAR2, message IN VARCHAR2) IS mailhost VARCHAR2(30) := 'mailhost.mydomain.com'; smtp_error EXCEPTION; mail_conn utl_tcp.connection; PROCEDURE smtp_command(command IN VARCHAR2, ok IN VARCHAR2 DEFAULT '250') IS response varchar2(3); len pls_integer; BEGIN len := utl_tcp.write_line(mail_conn, command); response := substr(utl_tcp.get_line(mail_conn), 1, 3); IF (response <> ok) THEN RAISE smtp_error; END IF; END;

BEGIN mail_conn := utl_tcp.open_connection(remote_host => mailhost, remote_port => 25, charset => 'US7ASCII'); smtp_command('HELO ' || mailhost); smtp_command('MAIL FROM: ' || sender); smtp_command('RCPT TO: ' || recipient); smtp_command('DATA', '354'); smtp_command(message); smtp_command('QUIT', '221'); utl_tcp.close_connection(mail_conn);EXCEPTION WHEN OTHERS THEN -- Handle the errorEND;

Summary of UTL_TCP Subprograms

Table 179-3 UTL_TCP Package Subprograms

Subprogram Description

AVAILABLE Function Determines the number of bytes available for reading from a TCP/IP connection

CLOSE_ALL_CONNECTIONS Procedure

Closes all open TCP/IP connections

www.saturninfotech.com

Page 64: Pl SQL Document by Mv

PL SQL Document 64

Subprogram Description

CLOSE_CONNECTION Procedure Closes an open TCP/IP connection

FLUSH Procedure Transmits all data in the output buffer, if a buffer is used, to the server immediately

GET_LINE Function Convenient forms of the read functions, which return the data read instead of the amount of data read

GET_RAW Function Convenient forms of the read functions, which return the data read instead of the amount of data read

GET_TEXT Function Convenient forms of the read functions, which return the data read instead of the amount of data read

OPEN_CONNECTION Function Opens a TCP/IP connection to a specified service

READ_LINE Function Receives a text line from a service on an open connection

READ_RAW Function Receives binary data from a service on an open connection

READ_TEXT Function Receives text data from a service on an open connection

WRITE_LINE Function Transmits a text line to a service on an open connection

WRITE_RAW Function Transmits a binary message to a service on an open connection

WRITE_TEXT Function Transmits a text message to a service on an open connection

AVAILABLE Function

This function determines the number of bytes available for reading from a TCP/IP connection. It is the number of bytes that can be read immediately without blocking. Determines if data is ready to be read from the connection.

Syntax

UTL_TCP.AVAILABLE ( c IN OUT NOCOPY connection, timeout IN PLS_INTEGER DEFAULT 0)RETURN num_bytes PLS_INTEGER;

Parameters

www.saturninfotech.com

Page 65: Pl SQL Document by Mv

PL SQL Document 65

Table 179-4 AVAILABLE Function Parameters

Parameter Description

c The TCP connection to determine the amount of data that is available to be read from.

timeout A time in seconds to wait before giving up and reporting that no data is available. Zero (0) indicates not to wait at all. NULL indicates to wait forever.

Return Values

Table 179-5 AVAILABLE Function Return Values

Parameter Description

num_bytes The number of bytes available for reading without blocking.

Usage Notes

The connection must have already been opened through a call to OPEN_CONNECTION. Users may use this API to determine if data is available to be read before calling the read API so that the program will not be blocked because data is not ready to be read from the input.

The number of bytes available for reading returned by this function may less than than what is actually available. On some platforms, this function may only return 1, to indicate that some data is available. If you are concerned about the portability of your application, assume that this function returns a positive value when data is available for reading, and 0 when no data is available. This function returns a positive value when all the data at a particular connection has been read and the next read will result in the END_OF_INPUT exception.

The following example illustrates using this function in a portable manner:

DECLARE c utl_tcp.connection data VARCHAR2(256); len PLS_INTEGER;BEGIN c := utl_tcp.open_connection(...); LOOP IF (utl_tcp.available(c) > 0) THEN len := utl_tcp.read_text(c, data, 256); ELSE ---do some other things

www.saturninfotech.com

Page 66: Pl SQL Document by Mv

PL SQL Document 66

. . . . END IF END LOOP;END;

Related Functions

READ_RAW, READ_TEXT, READ_LINE

CLOSE_ALL_CONNECTIONS Procedure

This procedure closes all open TCP/IP connections.

Syntax

UTL_TCP.CLOSE_ALL_CONNECTIONS;

Usage Notes

This call is provided to close all connections before a PL/SQL program avoid dangling connections.

Related Functions

OPEN_CONNECTION, CLOSE_CONNECTION.

CLOSE_CONNECTION Procedure

This procedure closes an open TCP/IP connection.

Syntax

UTL_TCP.CLOSE_CONNECTION ( c IN OUT NOCOPY connection);

Parameters

Table 179-6 CLOSE_CONNECTION Procedure Parameters

Parameter Description

c The TCP connection to close.

www.saturninfotech.com

Page 67: Pl SQL Document by Mv

PL SQL Document 67

Usage Notes

Connection must have been opened by a previous call to OPEN_CONNECTION. The fields remote_host, remote_port, local_host, local_port and charset of c will be reset after the connection is closed.

An open connection must be closed explicitly. An open connection will remain open when the PL/SQL record variable that stores the connection goes out-of-scope in the PL/SQL program. Failing to close unwanted connections may result in unnecessary tying up of local and remote system resources.

FLUSH Procedure

This procedure transmits all data in the output buffer, if a buffer is used, to the server immediately.

Syntax

UTL_TCP.FLUSH ( c IN OUT NOCOPY connection);

Parameters

Table 179-7 FLUSH Procedure Parameters

Parameter Description

c The TCP connection to send data to.

Usage Notes

The connection must have already been opened through a call to OPEN_CONNECTION.

Related Functions

WRITE_RAW, WRITE_TEXT, WRITE_LINE

www.saturninfotech.com

Page 68: Pl SQL Document by Mv

PL SQL Document 68

GET_LINE Function

This function returns the data read instead of the amount of data read.

Syntax

UTL_TCP.GET_LINE ( c IN OUT NOCOPY connection, remove_crlf IN BOOLEAN DEFAULT FALSE, peek IN BOOLEAN DEFAULT FALSE) RETURN VARCHAR2;

Parameters

Table 179-8 GET_LINE Function Parameters

Parameter Description

c The TCP connection to receive data from.

remove_crlf If TRUE, the trailing CR/LF character(s) are removed from the received message.

peek Normally, you want to read the data and remove it from the input queue, that is, consume it. In some situations, you may just want to look ahead at the data, that is, peek at it, without removing it from the input queue, so that it is still available for reading (or even peeking) in the next call. To keep the data in the input queue, set this flag to TRUE and set up an input buffer before the connection is opened. The amount of data you can peeked at (that is, read but keep in the input queue) must be less than the size of input buffer.

Usage Notes

The connection must have already been opened through a call to OPEN_CONNECTION. See READ_LINE for the read time out, character set conversion, buffer size, and multibyte

character issues.

Related Functions

GET_RAW, GET_TEXT, READ_LINE

GET_RAW Function

This function returns the data read instead of the amount of data read.

www.saturninfotech.com

Page 69: Pl SQL Document by Mv

PL SQL Document 69

Syntax

UTL_TCP.GET_RAW ( c IN OUT NOCOPY connection, len IN PLS_INTEGER DEFAULT 1, peek IN BOOLEAN DEFAULT FALSE) RETURN RAW;

Parameters

Table 179-9 GET_RAW Function Parameters

Parameter Description

c The TCP connection to receive data from.

len The number of bytes (or characters for VARCHAR2) of data to receive. Default is 1.

peek Normally, you want to read the data and remove it from the input queue, that is, consume it. In some situations, you may just want to look ahead at the data, that is, peek at it, without removing it from the input queue, so that it is still available for reading (or even peeking) in the next call. To keep the data in the input queue, set this flag to TRUE and set up an input buffer before the connection is opened. The amount of data you can peeked at (that is, read but keep in the input queue) must be less than the size of input buffer.

remove_crlf If TRUE, the trailing CR/LF character(s) are removed from the received message.

Usage Notes

The connection must have already been opened through a call to OPEN_CONNECTION.

For all the get_* APIs described in this section, see the corresponding READ_* API for the read time out issue. For GET_TEXT and GET_LINE, see the corresponding READ_* API for character set conversion, buffer size, and multibyte character issues.

Related Functions

GET_RAW, GET_TEXT, READ_RAW, READ_TEXT, READ_LINE

GET_TEXT Function

This function returns the data read instead of the amount of data read.

www.saturninfotech.com

Page 70: Pl SQL Document by Mv

PL SQL Document 70

Syntax

UTL_TCP.GET_TEXT ( c IN OUT NOCOPY connection, len IN PLS_INTEGER DEFAULT 1, peek IN BOOLEAN DEFAULT FALSE) RETURN VARCHAR2;

Parameters

Table 179-10 GET_TEXT Function Parameters

Parameter Description

c The TCP connection to receive data from.

len The number of bytes (or characters for VARCHAR2) of data to receive. Default is 1.

peek Normally, you want to read the data and remove it from the input queue, that is, consume it. In some situations, you may just want to look ahead at the data, that is, peek at it, without removing it from the input queue, so that it is still available for reading (or even peeking) in the next call. To keep the data in the input queue, set this flag to TRUE and set up an input buffer before the connection is opened. The amount of data you can peeked at (that is, read but keep in the input queue) must be less than the size of input buffer.

remove_crlf If TRUE, the trailing CR/LF character(s) are removed from the received message.

Usage Notes

The connection must have already been opened through a call to OPEN_CONNECTION.

For all the get_* APIs described in this section, see the corresponding read_* API for the read time out issue. For GET_TEXT and GET_LINE, see the corresponding READ_* API for character set conversion, buffer size, and multibyte character issues.

Related Functions

READ_RAW, READ_TEXT, READ_LINE

OPEN_CONNECTION Function

This function opens a TCP/IP connection to a specified service.

www.saturninfotech.com

Page 71: Pl SQL Document by Mv

PL SQL Document 71

Syntax

UTL_TCP.OPEN_CONNECTION ( remote_host IN VARCHAR2, remote_port IN PLS_INTEGER, local_host IN VARCHAR2 DEFAULT NULL, local_port IN PLS_INTEGER DEFAULT NULL, in_buffer_size IN PLS_INTEGER DEFAULT NULL, out_buffer_size IN PLS_INTEGER DEFAULT NULL, charset IN VARCHAR2 DEFAULT NULL, newline IN VARCHAR2 DEFAULT CRLF, tx_timeout IN PLS_INTEGER DEFAULT NULL) RETURN connection;

Parameters

Table 179-11 OPEN_CONNECTION Function Parameters

Parameter Description

remote_host The name of the host providing the service. When remote_host is NULL, it connects to the local host.

remote_port The port number on which the service is listening for connections.

local_host The name of the host providing the service. NULL means don't care.

local_port The port number on which the service is listening for connections. NULL means don't care.

in_buffer_size The size of input buffer. The use of an input buffer can speed up execution performance in receiving data from the server. The appropriate size of the buffer depends on the flow of data between the client and the server, and the network condition. A 0 value means no buffer should be used. A NULL value means the caller does not care if a buffer is used or not. The maximum size of the input buffer is 32767 bytes.

out_buffer_size The size of output buffer. The use of an output buffer can speed up execution performance in sending data to the server. The appropriate size of buffer depends on the flow of data between the client and the server, and the network condition. A 0 value means no buffer should be used. A NULL value means the caller does not care if a buffer is used or not. The maximum size of the output buffer is 32767 bytes.

charset The on-the-wire character set. Since text messages in the database may be encoded in a character set that is different from the one expected on the wire (that is, the character set specified by the communication protocol, or the one stipulated by the other end of the communication), text messages in the database will be converted to and from the on-the-wire character set as they are sent and received on the network using READ_TEXT, READ_LINE,

www.saturninfotech.com

Page 72: Pl SQL Document by Mv

PL SQL Document 72

Parameter Description

WRITE_TEXT and WRITE_LINE. Set this parameter to NULL when no conversion is needed.

newline The newline character sequence. This newline character sequence is appended to the text line sent by WRITE_LINE API.

tx_timeout A time in seconds that the UTL_TCP package should wait before giving up in a read or write operations in this connection. In read operations, this package gives up if no data is available for reading immediately. In write operations, this package gives up if the output buffer is full and no data is to be sent in the network without being blocked. Zero (0) indicates not to wait at all. NULL indicates to wait forever.

Return Values

Table 179-12 OPEN_CONNECTION Function Return Values

Parameter Description

connection A connection to the targeted TCP/IP service.

Usage Notes

Note that connections opened by this UTL_TCP package can remain open and be passed from one database call to another in a shared server configuration. However, the connection must be closed explicitly. The connection will remain open when the PL/SQL record variable that stores the connection goes out-of-scope in the PL/SQL program. Failing to close unwanted connections may result in unnecessary tying up of local and remote system resources.

In the current release of the UTL_TCP package, the parameters local_host and local_port are ignored when open_connection makes a TCP/IP connection. It does not attempt to use the specified local host and port number when the connection is made. The local_host and local_port fields will not be set in the connection record returned by the function.

Time out on write operations is not supported in the current release of the UTL_TCP package.

Related Functions

CLOSE_CONNECTION, CLOSE_ALL_CONNECTIONS

www.saturninfotech.com

Page 73: Pl SQL Document by Mv

PL SQL Document 73

READ_LINE Function

This function receives a text line from a service on an open connection. A line is terminated by a line-feed, a carriage-return or a carriage-return followed by a line-feed.

Syntax

UTL_TCP.READ_LINE ( c IN OUT NOCOPY connection, data IN OUT NOCOPY VARCHAR2 CHARACTER SET ANY_CS, peek IN BOOLEAN DEFAULT FALSE) RETURN num_chars PLS_INTEGER;

Parameters

Table 179-13 READ_LINE Function Parameters

Parameter Description

c The TCP connection to receive data from.

data The data received.

remove_crlf If TRUE, the trailing CR/LF character(s) are removed from the received message.

peek Normally, you want to read the data and remove it from the input queue, that is, consume it. In some situations, you may just want to look ahead at the data, that is, peek at it, without removing it from the input queue, so that it is still available for reading (or even peeking) in the next call. To keep the data in the input queue, set this flag to TRUE and set up an input buffer before the connection is opened. The amount of data you can peeked at (that is, read but keep in the input queue) must be less than the size of input buffer.

Return Values

Table 179-14 READ_LINE Function Return Values

Parameter Description

num_chars The actual number of characters of data received.

Usage Notes

www.saturninfotech.com

Page 74: Pl SQL Document by Mv

PL SQL Document 74

The connection must have already been opened through a call to OPEN_CONNECTION. This function does not return until the end-of-line have been reached, or the end of input has been reached. Text messages will be converted from the on-the-wire character set, specified when the connection was opened, to the database character set before they are returned to the caller.

If transfer time out is set when the connection is opened, this function waits for each data packet to be ready to read until time out occurs. If it occurs, this function stops reading and returns all the data read successfully. If no data is read successfully, the transfer_timeout exception is raised. The exception can be handled and the read operation can be retried later.

If a partial multibyte character is found at the end of input, this function stops reading and returns all the complete multibyte characters read successfully. If no complete character is read successfully, the partial_multibyte_char exception is raised. The exception can be handled and the bytes of that partial multibyte character can be read as binary by the READ_RAW function. If a partial multibyte character is seen in the middle of the input because the remaining bytes of the character have not arrived and read time out occurs, the transfer_timeout exception is raised instead. The exception can be handled and the read operation can be retried later.

Related Functions

READ_RAW, READ_TEXT, AVAILABLE

READ_RAW Function

This function receives binary data from a service on an open connection.

Syntax

UTL_TCP.READ_RAW ( c IN OUT NOCOPY connection, data IN OUT NOCOPY RAW, len IN PLS_INTEGER DEFAULT 1, peek IN BOOLEAN DEFAULT FALSE) RETURN num_bytes PLS_INTEGER;

Parameters

Table 179-15 READ_RAW Function Parameters

Parameter Description

c The TCP connection to receive data from.

data (IN The data received.

www.saturninfotech.com

Page 75: Pl SQL Document by Mv

PL SQL Document 75

Parameter Description

OUT COPY)

len The number of bytes of data to receive.

peek Normally, you want to read the data and remove it from the input queue, that is, consume it. In some situations, you may just want to look ahead at the data, that is, peek at it, without removing it from the input queue, so that it is still available for reading (or even peeking) in the next call. To keep the data in the input queue, set this flag to TRUE and set up an input buffer before the connection is opened. The amount of data you can peeked at (that is, read but keep in the input queue) must be less than the size of input buffer.

Return Values

Table 179-16 READ_RAW Function Return Values

Parameter Description

num_bytes The actual number of bytes of data received.

Usage Notes

The connection must have already been opened through a call to OPEN_CONNECTION. This function does not return until the specified number of bytes have been read, or the end of input has been reached.

If transfer time out is set when the connection is opened, this function waits for each data packet to be ready to read until time out occurs. If it occurs, this function stops reading and returns all the data read successfully. If no data is read successfully, the transfer_timeout exception is raised. The exception can be handled and the read operation can be retried later.

Related Functions

READ_TEXT, READ_LINE, AVAILABLE

READ_TEXT Function

This function receives text data from a service on an open connection.

www.saturninfotech.com

Page 76: Pl SQL Document by Mv

PL SQL Document 76

Syntax

UTL_TCP.READ_TEXT ( c IN OUT NOCOPY connection, data IN OUT NOCOPY VARCHAR2 CHARACTER SET ANY_CS, len IN PLS_INTEGER DEFAULT 1, peek IN BOOLEAN DEFAULT FALSE) RETURN num_chars PLS_INTEGER;

Parameters

Table 179-17 READ_TEXT Function Parameters

Parameter Description

c The TCP connection to receive data from.

data The data received.

len The number of characters of data to receive.

peek Normally, users want to read the data and remove it from the input queue, that is, consume it. In some situations, users may just want to look ahead at the data without removing it from the input queue so that it is still available for reading (or even peeking) in the next call. To keep the data in the input queue, set this flag to TRUE and an input buffer must be set up when the connection is opened. The amount of data that you can peek at (that is, read but keep in the input queue) must be less than the size of input buffer.

Return Values

Table 179-18 READ_TEXT Function Return Values

Parameter Description

num_chars The actual number of characters of data received.

Usage Notes

The connection must have already been opened through a call to OPEN_CONNECTION. This function does not return until the specified number of characters has been read, or the end of input has been reached. Text messages will be converted from the on-the-wire character set, specified when the connection was opened, to the database character set before they are returned to the caller.

www.saturninfotech.com

Page 77: Pl SQL Document by Mv

PL SQL Document 77

Unless explicitly overridden, the size of a VARCHAR2 buffer is specified in terms of bytes, while the parameter len refers to the maximum number of characters to be read. When the database character set is multibyte, where a single character may consist of more than 1 byte, you should ensure that the buffer can hold the maximum of characters. In general, the size of the VARCHAR2 buffer should equal the number of characters to be read, multiplied by the maximum number of bytes of a character of the database character set.

If transfer time out is set when the connection is opened, this function waits for each data packet to be ready to read until time out occurs. If it occurs, this function stops reading and returns all the data read successfully. If no data is read successfully, the transfer_timeout exception is raised. The exception can be handled and the read operation can be retried later.

If a partial multibyte character is found at the end of input, this function stops reading and returns all the complete multibyte characters read successfully. If no complete character is read successfully, the partial_multibyte_char exception is raised. The exception can be handled and the bytes of that partial multibyte character can be read as binary by the READ_RAW function. If a partial multibyte character is seen in the middle of the input because the remaining bytes of the character have not arrived and read time out occurs, the transfer_timeout exception is raised instead. The exception can be handled and the read operation can be retried later.

Related Functions

READ_RAW, READ_LINE, AVAILABLE

WRITE_LINE Function

This function transmits a text line to a service on an open connection. The newline character sequence will be appended to the message before it is transmitted.

Syntax

UTL_TCP.WRITE_LINE ( c IN OUT NOCOPY connection, data IN VARCHAR2 DEFAULT NULL CHARACTER SET ANY_CS) RETURN PLS_INTEGER;

Parameters

Table 179-19 WRITE_LINE Function Parameters

Parameter Description

c The TCP connection to send data to.

www.saturninfotech.com

Page 78: Pl SQL Document by Mv

PL SQL Document 78

Parameter Description

data The buffer containing the data to be sent.

Return Values

Table 179-20 WRITE_LINE Function Return Values

Parameter Description

num_chars The actual number of characters of data transmitted.

Usage Notes

The connection must have already been opened through a call to OPEN_CONNECTION. Text messages will be converted to the on-the-wire character set, specified when the connection was opened, before they are transmitted on the wire.

Related Functions

WRITE_RAW, WRITE_TEXT, FLUSH

WRITE_RAW Function

This function transmits a binary message to a service on an open connection. The function does not return until the specified number of bytes have been written.

Syntax

UTL_TCP.WRITE_RAW ( c IN OUT NOCOPY connection, data IN RAW, len IN PLS_INTEGER DEFAULT NULL) RETURN num_bytes PLS_INTEGER;

Parameters

Table 179-21 WRITE_RAW Function Parameters

www.saturninfotech.com

Page 79: Pl SQL Document by Mv

PL SQL Document 79

Parameter Description

c The TCP connection to send data to.

data The buffer containing the data to be sent.

len The number of bytes of data to transmit. When len is NULL, the whole length of data is written.

Return Values

Table 179-22 WRITE_RAW Function Return Values

Parameter Description

num_bytes The actual number of bytes of data transmitted.

Usage Notes

The connection must have already been opened through a call to OPEN_CONNECTION.

Related Functions

WRITE_TEXT, WRITE_LINE, FLUSH

WRITE_TEXT Function

This function transmits a text message to a service on an open connection.

Syntax

UTL_TCP.WRITE_TEXT ( c IN OUT NOCOPY connection, data IN VARCHAR2 CHARACTER SET ANY_CS, len IN PLS_INTEGER DEFAULT NULL) RETURN num_chars PLS_INTEGER;

Parameters

Table 179-23 WRITE_TEXT Function Parameters

www.saturninfotech.com

Page 80: Pl SQL Document by Mv

PL SQL Document 80

Parameter Description

c The TCP connection to send data to.

data The buffer containing the data to be sent.

len The number of characters of data to transmit. When len is NULL, the whole length of data is written. The actual amount of data written may be less because of network condition.

Return Values

Table 179-24 WRITE_TEXT Function Return Values

Parameter Description

num_chars The actual number of characters of data transmitted.

Usage Notes

The connection must have already been opened through a call to OPEN_CONNECTION. Text messages will be converted to the on-the-wire character set, specified when the connection was opened, before they are transmitted on the wire.

Related Functions

WRITE_RAW, WRITE_LINE, FLUSH

www.saturninfotech.com

Page 81: Pl SQL Document by Mv

PL SQL Document 81

UTL_URL

The UTL_URL package has two functions: ESCAPE and UNESCAPE.

See Also:

Chapter 169, "UTL_HTTP"

This chapter contains the following topics:

Using UTL_URL o Overviewo Exceptionso Examples

Summary of UTL_URL Subprograms

Using UTL_URL

Overview Exceptions Examples

Overview

A Uniform Resource Locator (URL) is a string that identifies a Web resource, such as a page or a picture. Use a URL to access such resources by way of the HyperText Transfer Protocol (HTTP). For example, the URL for Oracle's Web site is:

http://www.oracle.com

Normally, a URL contains English alphabetic characters, digits, and punctuation symbols. These characters are known as the unreserved characters. Any other characters in URLs, including multibyte characters or binary octet codes, must be escaped to be accurately processed by Web browsers or Web servers. Some punctuation characters, such as dollar sign ($), question mark (?), colon (:), and equals sign (=), are reserved as delimiters in a URL. They are known as the reserved characters. To literally process these characters, instead of treating them as delimiters, they must be escaped.

The unreserved characters are:

www.saturninfotech.com

Page 82: Pl SQL Document by Mv

PL SQL Document 82

A through Z, a through z, and 0 through 9 Hyphen (-), underscore (_), period (.), exclamation point (!), tilde (~), asterisk (*),

accent ('), left parenthesis ( ( ), right parenthesis ( ) )

The reserved characters are:

Semi-colon (;) slash (/), question mark (?), colon (:), at sign (@), ampersand (&), equals sign (=), plus sign (+), dollar sign ($), and comma (,)

The UTL_URL package has two functions that provide escape and unescape mechanisms for URL characters. Use the escape function to escape a URL before the URL is used fetch a Web page by way of the UTL_HTTP package. Use the unescape function to unescape an escaped URL before information is extracted from the URL.

For more information, refer to the Request For Comments (RFC) document RFC2396. Note that this URL escape and unescape mechanism is different from the x-www-form-urlencoded encoding mechanism described in the HTML specification:

http://www.w3.org/TR/html

Exceptions

Table 180-1 lists the exceptions that can be raised when the UTL_URL package API is invoked.

Table 180-1 UTL_URL Exceptions

ExceptionError Code Reason

BAD_URL 29262 The URL contains badly formed escape code sequences

BAD_FIXED_WIDTH_CHARSET

29274 Fixed-width multibyte character set is not allowed as a URL character set.

Examples

You can implement the x-www-form-urlencoded encoding using the UTL_URL.ESCAPE function as follows:

CREATE OR REPLACE FUNCTION form_url_encode (

www.saturninfotech.com

Page 83: Pl SQL Document by Mv

PL SQL Document 83

data IN VARCHAR2, charset IN VARCHAR2) RETURN VARCHAR2 AS BEGIN RETURN utl_url.escape(data, TRUE, charset); -- note use of TRUEEND;

For decoding data encoded with the form-URL-encode scheme, the following function implements the decording scheme:

CREATE OR REPLACE FUNCTION form_url_decode( data IN VARCHAR2, charset IN VARCHAR2) RETURN VARCHAR2 ASBEGIN RETURN utl_url.unescape( replace(data, '+', ' '), charset); END;

Summary of UTL_URL Subprograms

Table 180-2 UTL_URL Package Subprograms

Subprogram Description

ESCAPE Function

Returns a URL with illegal characters (and optionally reserved characters) escaped using the %2-digit-hex-code format

UNESCAPE Function

Unescapes the escape character sequences to their original forms in a URL. Convert the %XX escape character sequences to the original characters

ESCAPE Function

This function returns a URL with illegal characters (and optionally reserved characters) escaped using the %2-digit-hex-code format.

Syntax

UTL_URL.ESCAPE ( url IN VARCHAR2 CHARACTER SET ANY_CS, escape_reserved_chars IN BOOLEAN DEFAULT FALSE, url_charset IN VARCHAR2 DEFAULT utl_http.body_charset) RETURN VARCHAR2;

Parameters

www.saturninfotech.com

Page 84: Pl SQL Document by Mv

PL SQL Document 84

Table 180-3 ESCAPE Function Parameters

Parameter Description

url The original URL

escape_reserved_chars

Indicates whether the URL reserved characters should be escaped. If set to TRUE, both the reserved and illegal URL characters are escaped. Otherwise, only the illegal URL characters are escaped. The default value is FALSE.

url_charset When escaping a character (single-byte or multibyte), determine the target character set that character should be converted to before the character is escaped in %hex-code format. If url_charset is NULL, the database charset is assumed and no character set conversion will occur. The default value is the current default body character set of the UTL_HTTP package, whose default value is ISO-8859-1. The character set can be named in Internet Assigned Numbers Authority (IANA) or in the Oracle naming convention.

Usage Notes

Use this function to escape URLs that contain illegal characters as defined in the URL specification RFC 2396. The legal characters in URLs are:

A through Z, a through z, and 0 through 9 Hyphen (-), underscore (_), period (.), exclamation point (!), tilde (~), asterisk (*),

accent ('), left parenthesis ( ( ), right parenthesis ( ) )

The reserved characters consist of:

Semi-colon (;) slash (/), question mark (?), colon (:), at sign (@), ampersand (&), equals sign (=), plus sign (+), dollar sign ($), and comma (,)

Many of the reserved characters are used as delimiters in the URL. You should escape characters beyond those listed here by using escape_url. Also, to use the reserved characters in the name-value pairs of the query string of a URL, those characters must be escaped separately. An escape_url cannot recognize the need to escape those characters because once inside a URL, those characters become indistinguishable from the actual delimiters. For example, to pass a name-value pair $logon=scott/tiger into the query string of a URL, escape the $ and / separately as %24logon=scott%2Ftiger and use it in the URL.

Normally, you will escape the entire URL, which contains the reserved characters (delimiters) that should not be escaped. For example:

www.saturninfotech.com

Page 85: Pl SQL Document by Mv

PL SQL Document 85

utl_url.escape('http://www.acme.com/a url with space.html')

Returns:

In other situations, you may want to send a query string with a value that contains reserved characters. In that case, escape only the value fully (with escape_reserved_chars set to TRUE) and then concatenate it with the rest of the URL. For example:

url := 'http://www.acme.com/search?check=' || utl_url.escape('Is the use of the "$" sign okay?', TRUE);

This expression escapes the question mark (?), dollar sign ($), and space characters in 'Is the use of the "$" sign okay?' but not the ? after search in the URL that denotes the use of a query string.

The Web server that you intend to fetch Web pages from may use a character set that is different from that of your database. In that case, specify the url_charset as the Web server character set so that the characters that need to be escaped are escaped in the target character set. For example, a user of an EBCDIC database who wants to access an ASCII Web server should escape the URL using US7ASCII so that a space is escaped as %20 (hex code of a space in ASCII) instead of %40 (hex code of a space in EBCDIC).

This function does not validate a URL for the proper URL format.

UNESCAPE Function

This function unescapes the escape character sequences to its original form in a URL, to convert the %XX escape character sequences to the original characters.

Syntax

UTL_URL.UNESCAPE ( url IN VARCHAR2 CHARACTER SET ANY_CS, url_charset IN VARCHAR2 DEFAULT utl_http.body_charset) RETURN VARCHAR2;

Parameters

Table 180-4 UNESCAPE Function Parameters

Parameter Description

url The URL to unescape

www.saturninfotech.com

Page 86: Pl SQL Document by Mv

PL SQL Document 86

Parameter Description

url_charset After a character is unescaped, the character is assumed to be in the source_charset character set and it will be converted from the source_charset to the database character set before the URL is returned. If source_charset is NULL, the database charset is assumed and no character set conversion occurred. The default value is the current default body character set of the UTL_HTTP package, whose default value is "ISO-8859-1". The character set can be named in Internet Assigned Numbers Authority (IANA) or Oracle naming convention.

Usage Notes

The Web server that you receive the URL from may use a character set that is different from that of your database. In that case, specify the url_charset as the Web server character set so that the characters that need to be unescaped are unescaped in the source character set. For example, a user of an EBCDIC database who receives a URL from an ASCII Web server should unescape the URL using US7ASCII so that %20 is unescaped as a space (0x20 is the hex code of a space in ASCII) instead of a ? (because 0x20 is not a valid character in EBCDIC).

This function does not validate a URL for the proper URL format.

www.saturninfotech.com

Page 87: Pl SQL Document by Mv

PL SQL Document 87

PL/SQL forall operator

Loading an Oracle table from a PL/SQL array involves expensive context switches, and the PL/SQL FORALL operator speed is amazing.

The best overall reference of hypercharging PL/SQL table insert performance with forall array collections is Dr. Tim Hall (Oracle ACE of the year 2006) and his landmark book "Oracle PL/SQL Tuning: Expert Secrets for High Performance Programming".

Kent Crotty, author of Easy Oracle Application Express (HTML-DB) conducted a study to prove the speed of the PL/SQL forall over vanilla SQL inserts, and found that FORALL was 30x faster in his small test:

DECLARETYPE prod_tab IS TABLE OF products%ROWTYPE;products_tab   prod_tab := prod_tab();start_time  number;  end_time   number;BEGIN-- Populate a collection - 100000 rowsSELECT * BULK COLLECT INTO products_tab FROM products; EXECUTE IMMEDIATE 'TRUNCATE TABLE products';Start_time := DBMS_UTILITY.get_time;FOR i in products_tab.first .. products_tab.last LOOP INSERT INTO products (product_id, product_name, effective_date)   VALUES (products_tab(i).product_id, products_tab(i).product_name,           products_tab(i).effective_date);END LOOP;end_time := DBMS_UTILITY.get_time;DBMS_OUTPUT.PUT_LINE(‘Conventional Insert: ’||to_char(end_time-start_time)); EXECUTE IMMEDIATE 'TRUNCATE TABLE products';Start_time := DBMS_UTILITY.get_time;FORALL i in products_tab.first .. products_tab.last INSERT INTO products VALUES products_tab(i);end_time := DBMS_UTILITY.get_time;DBMS_OUTPUT.PUT_LINE(‘Bulk Insert: ’||to_char(end_time-start_time));COMMIT;END;

Crotty notes a great speed improvement with very few code changes, from 622 seconds to only 22 seconds:

SQL> /

Conventional Insert: 686

Bulk Insert: 22

www.saturninfotech.com

Page 88: Pl SQL Document by Mv

PL SQL Document 88

Using Bulk Binds And Oracle FORALL

Yesterday, I looked at collections, an evolution of PL/SQL tables that allows us to manipulate many variables at once, as a unit. Collections, coupled with two new features introduced with Oracle 8i, Oracle BULK_COLLECT and Oracle FORALL, can dramatically increase the performance of data manipulation code within PL/SQL.

As a reminder, we were looking at a piece of code that implemented collections, Oracle BULK COLLECT and Oracle FORALL, taken from a question and answer posed online by Daniel Morgan.

CREATE OR REPLACE PROCEDURE fast_proc (p_array_size IN PLS_INTEGER DEFAULT 100)IS

TYPE ARRAY IS TABLE OF all_objects%ROWTYPE;l_data ARRAY;

CURSOR c ISSELECT *FROM all_objects;

BEGIN    OPEN c;    LOOP    FETCH c BULK COLLECT INTO l_data LIMIT p_array_size;

    FORALL i IN 1..l_data.COUNT    INSERT INTO t2 VALUES l_data(i);

    EXIT WHEN c%NOTFOUND;    END LOOP;    CLOSE c;END fast_proc;/

which was subsequently refined in a later answer to;

SQL> create or replace procedure fast_proc is2         type TObjectTable is table of ALL_OBJECTS%ROWTYPE;3         ObjectTable$ TObjectTable;4         begin5         select6                     * BULK COLLECT INTO ObjectTable$7         from ALL_OBJECTS;89         forall x in ObjectTable$.First..ObjectTable$.Last

www.saturninfotech.com

Page 89: Pl SQL Document by Mv

PL SQL Document 89

10       insert into t1 values ObjectTable$(x) ;11       end;12 /

The key things here are the collection that is set up to hold the table data, the BULK COLLECT clause and the Oracle FORALL statement. I went into detail about the collection yesterday, so now it's time to look at the other two.

Steven Feuernstein explains the basics behind BULK_COLLECT and Oracle FORALL in a recent OTN article, and together these two features are known as 'Bulk Binding'. Bulk Binds are a PL/SQL technique where, instead of multiple individual SELECT, INSERT, UPDATE or DELETE statements are executed to retrieve from, or store data in, at table, all of the operations are carried out at once, in bulk. This avoids the context-switching you get when the PL/SQL engine has to pass over to the SQL engine, then back to the PL/SQL engine, and so on, when you individually access rows one at a time. To do bulk binds with INSERT, UPDATE, and DELETE statements, you enclose the SQL statement within a PL/SQL FORALL statement. To do bulk binds with SELECT statements, you include the BULK COLLECT clause in the SELECT statement instead of using INTO.

www.saturninfotech.com

Page 90: Pl SQL Document by Mv

PL SQL Document 90

SELECT FOR UPDATE in Cursors

When you issue a SELECT statement against the database to query some records, no locks are placed on the selected rows. In general, this is a wonderful feature because the number of records locked at any given time is (by default) kept to the absolute minimum: only those records which have been changed but not yet committed are locked. Even then, others will be able to read those records as they appeared before the change (the "before image" of the data).

There are times, however, when you will want to lock a set of records even before you change them in your program. Oracle offers the FOR UPDATE clause of the SELECT statement to perform this locking.

When you issue a SELECT...FOR UPDATE statement, the RDBMS automatically obtains exclusive row-level locks on all the rows identified by the SELECT statement, holding the records "for your changes only" as you move through the rows retrieved by the cursor. No one else will be able to change any of these records until you perform a ROLLBACK or a COMMIT.

Here are two examples of the FOR UPDATE clause used in a cursor:

CURSOR toys_cur IS SELECT name, manufacturer, preference_level, sell_at_yardsale_flag FROM my_sons_collection WHERE hours_used = 0 FOR UPDATE;

CURSOR fall_jobs_cur IS SELECT task, expected_hours, tools_required, do_it_yourself_flag FROM winterize WHERE year = TO_CHAR (SYSDATE, 'YYYY') FOR UPDATE OF task;

The first cursor uses the unqualified FOR UPDATE clause, while the second cursor qualifies the FOR UPDATE with a column name from the query.

You can use the FOR UPDATE clause in a SELECT against multiple tables. In this case, rows in a table are locked only if the FOR UPDATE clause references a column in that table. In the following example the FOR UPDATE clause does not result in any locked rows in the winterize table:

CURSOR fall_jobs_cur IS SELECT w.task, w.expected_hours, w.tools_required, w.do_it_yourself_flag FROM winterize w, husband_config hc WHERE year = TO_CHAR (SYSDATE, 'YYYY') FOR UPDATE OF husband_config.max_procrastination_allowed;

The FOR UPDATE OF clause only mentions the max_procrastination_allowed column; no columns in the winterize table are listed.

www.saturninfotech.com

Page 91: Pl SQL Document by Mv

PL SQL Document 91

The OF list of the FOR UPDATE clause does not restrict you to changing only those columns listed. Locks are still placed on all rows; the OF list just gives you a way to document more clearly what you intend to change. If you simply state FOR UPDATE in the query and do not include one or more columns after the OF keyword, then the database will then lock all identified rows across all tables listed in the FROM clause.

Furthermore, you do not have to actually UPDATE or DELETE any records just because you issued a SELECT...FOR UPDATE -- that act simply states your intention to be able to do so.

Finally, you can append the optional keyword NOWAIT to the FOR UPDATE clause to tell Oracle not to wait if the table has been locked by another user. In this case, control will be returned immediately to your program so that you can perform other work or simply wait for a period of time before trying again. Without the NOWAIT clause, your process will block until the table is available. There is no limit to the wait time unless the table is remote. For remote objects, the Oracle initialization parameter, DISTRIBUTED_LOCK_TIMEOUT, is used to set the limit.

6.11.1 Releasing Locks with COMMIT

As soon as a cursor with a FOR UPDATE clause is OPENed, all rows identified in the result set of the cursor are locked and remain locked until your session issues either a COMMIT statement to save any changes or a ROLLBACK statement to cancel those changes. When either of these actions occurs, the locks on the rows are released. As a result, you cannot execute another FETCH against a FOR UPDATE cursor after you COMMIT or ROLLBACK. You will have lost your position in the cursor.

Consider the following program, which assigns winterization chores:[1]

[1] Caveat: I don't want to set false expectations with anyone, especially my wife. The code in this block is purely an example. In reality, I set the max_procrastination_allowed to five years and let my house decay until I can afford to pay someone to do something, or my wife does it, or she gives me an ultimatum. Now you know why I decided to write a book...

DECLARE /* All the jobs in the Fall to prepare for the Winter */ CURSOR fall_jobs_cur IS SELECT task, expected_hours, tools_required, do_it_yourself_flag FROM winterize WHERE year = TO_CHAR (SYSDATE, 'YYYY') AND completed_flag = 'NOTYET' FOR UPDATE OF task;BEGIN /* For each job fetched by the cursor... */ FOR job_rec IN fall_jobs_cur LOOP IF job_rec.do_it_yourself_flag = 'YOUCANDOIT' THEN

www.saturninfotech.com

Page 92: Pl SQL Document by Mv

PL SQL Document 92

/* || I have found my next job. Assign it to myself (like someone || is going to do it!) and then commit the changes. */ UPDATE winterize SET responsible = 'STEVEN' WHERE task = job_rec.task AND year = TO_CHAR (SYSDATE, 'YYYY'); COMMIT; END IF; END LOOP;END;

Suppose this loop finds its first YOUCANDOIT job. It then commits an assignment of a job to STEVEN. When it tries to FETCH the next record, the program raises the following exception:

ORA-01002: fetch out of sequence

If you ever need to execute a COMMIT or ROLLBACK as you FETCH records from a SELECT FOR UPDATE cursor, you should include code (such as a loop EXIT or other conditional logic) to halt any further fetches from the cursor.

The WHERE CURRENT OF Clause

PL/SQL provides the WHERE CURRENT OF clause for both UPDATE and DELETE statements inside a cursor in order to allow you to easily make changes to the most recently fetched row of data.

The general format for the WHERE CURRENT OF clause is as follows:

UPDATE table_name SET set_clause WHERE CURRENT OF cursor_name;

DELETE FROM table_name WHERE CURRENT OF cursor_name;

Notice that the WHERE CURRENT OF clause references the cursor and not the record into which the next fetched row is deposited.

The most important advantage to using WHERE CURRENT OF where you need to change the row fetched last is that you do not have to code in two (or more) places the criteria used to uniquely identify a row in a table. Without WHERE CURRENT OF, you would need to repeat the WHERE clause of your cursor in the WHERE clause of the associated UPDATEs and DELETEs. As a result, if the table structure changes in a way that affects the construction of the primary key, you have to make sure that each SQL statement is upgraded to support this change. If you use WHERE CURRENT OF, on the other hand, you only have to modify the WHERE clause of the SELECT statement.

www.saturninfotech.com

Page 93: Pl SQL Document by Mv

PL SQL Document 93

This might seem like a relatively minor issue, but it is one of many areas in your code where you can leverage subtle features in PL/SQL to minimize code redundancies. Utilization of WHERE CURRENT OF, %TYPE, and %ROWTYPE declaration attributes, cursor FOR loops, local modularization, and other PL/SQL language constructs can have a big impact on reducing the pain you may experience when you maintain your Oracle-based applications.

Let's see how this clause would improve the previous example. In the jobs cursor FOR loop above, I want to UPDATE the record that was currently FETCHed by the cursor. I do this in the UPDATE statement by repeating the same WHERE used in the cursor because (task, year) makes up the primary key of this table:

WHERE task = job_rec.task AND year = TO_CHAR (SYSDATE, 'YYYY');

This is a less than ideal situation, as explained above: I have coded the same logic in two places, and this code must be kept synchronized. It would be so much more convenient and natural to be able to code the equivalent of the following statements:

Delete the record I just fetched.

or:

Update these columns in that row I just fetched.

A perfect fit for WHERE CURRENT OF! The next version of my winterization program below uses this clause. I have also switched to a simple loop from FOR loop because I want to exit conditionally from the loop:

DECLARE CURSOR fall_jobs_cur IS SELECT ... same as before ... ; job_rec fall_jobs_cur%ROWTYPE;BEGIN OPEN fall_jobs_cur; LOOP FETCH fall_jobs_cur INTO job_rec;

IF fall_jobs_cur%NOTFOUND THEN EXIT;

ELSIF job_rec.do_it_yourself_flag = 'YOUCANDOIT' THEN UPDATE winterize SET responsible = 'STEVEN' WHERE CURRENT OF fall_jobs_cur; COMMIT; EXIT; END IF; END LOOP;

www.saturninfotech.com

Page 94: Pl SQL Document by Mv

PL SQL Document 94

CLOSE fall_jobs_cur;END;

www.saturninfotech.com