About PL/SQL Procedural Language/SQL (PL/SQL) is Oracle Corporation’s procedural language extension to SQL, the standard data

access language for relational databases. PL/SQL offers modern software engineering features such as data encapsulation, exception handling, information hiding, object orientation, and brings state-of-the-art programming to the Oracle Server and toolset PL/SQL Environment Blocks of PL/SQL are passed to and processed by a PL/SQL engine, which may reside within the tool or within the Oracle server. When you submit PL/SQL blocks from a Oracle precompiler such as Pro*C or Pro*Cobol program, userexit, iSQL*Plus, or Server Manager, the PL/SQL engine in the Oracle Server processes them. It separates the SQL statements and sends them individually to the SQL statements executor. Benefits PL/SQL plays a central role in both the Oracle server (through stored procedures, stored functions, database triggers, and packages) and Oracle development tools (through Oracle Developer component triggers). PL/SQL can be used to group SQL statements together within a single block and to send the entire block to the server in a single call, thereby reducing networking traffic Break down a complex problem into a set of manageable, well-defined, logical modules and implement the modules with blocks. Prtable-SQL. In other words, PL/SQL programs can run anywhere the Oracle server can run; you do not need to tailor them to each new environment. Declare variables, cursors, constants, and exceptions and then use them in SQL and procedural statements Procedural Language Control Structures allow you to do the following: • Execute a sequence of statements conditionally • Execute a sequence of statements iteratively in a loop The Error handling functionality in PL/SQL allows you to do the following: • Process Oracle server errors with exception-handling routines • Declare user-defined error conditions and process them with exception-handling routines • Easy maintenance that enables you to modify: – Routines online without interfering with other users – One routine to affect multiple applications – One routine to eliminate duplicate testing • Improved data security and integrity by doing the following: – Control indirect access to database objects from nonprivileged users with security privileges – Ensure that related actions are performed together, or not at all, by funneling activity for related tables through a single path • Improved performance that allows you to do the following: – Avoid reparsing for multiple users by exploiting the shared SQL area – Avoid PL/SQL parsing at run time by parsing at compile time – Reduce the number of calls to the database and decrease network traffic by bundling commands • Improved code clarity: Using appropriate identifier names to describe the action of the routines reduces the need for comments and enhances the clarity of the code. programs can be divided into logical blocks. A PL/SQL block consists of up to three sections: declarative (optional), executable (required), and exception handling (optional). The following table describes the three sections: Section Description Inclusion Declarative Contains all variables, constants, cursors, and user-defined exceptions that are referenced in the executable and declarative sections Optional Executable Contains SQL statements to manipulate data in the database and PL/SQL statements to manipulate data in the block Mandatory Exception handling

Specifies the actions to perform when errors and abnormal conditions arise in the executable section Optional Section keywords DECLARE, BEGIN, and EXCEPTION are not followed by semicolons. • END and all other PL/SQL statements require a semicolon to terminate the statement. Variables can be used for: • Temporary storage of data • Manipulation of stored values • Reusability • Ease of maintenance PL/SQL variables: – Scalar – Composite – Reference – LOB (large objects) Non-PL/SQL variables: Bind and host variables iSQL*Plus host (or “bind”) variables can be used to pass run time values out of the PL/SQL block back to the iSQL*Plus environment. identifier [CONSTANT] datatype [NOT NULL] [:= | DEFAULT expr]; DECLARE v_hiredate DATE; v_deptno NUMBER(2) NOT NULL := 10; v_location VARCHAR2(13) := 'Atlanta'; c_comm CONSTANT NUMBER := 1400; Two variables can have the same name, provided they are in different blocks. CHAR [(maximum_length)] • VARCHAR2 (maximum_length) • LONG • LONG RAW • NUMBER [(precision, scale)] • BINARY_INTEGER • PLS_INTEGER • BOOLEAN TRUE, FALSE, or NULL. Rather than hard coding the data type and precision of a variable, you can use the %TYPE attribute to declare a variable according to another previously declared variable or database column. The %TYPE attribute is most often used when the value stored in the variable will be derived from a table in the database. A NOT NULL database column constraint does not apply to variables that are declared using %TYPE. v_name employees.last_name%TYPE; v_balance NUMBER(7,2); v_min_balance v_balance%TYPE := 10; TheCLOB (character large object) data type is used to store large blocks of single-byte character data in the database in line (inside the row) or out of line (outside the row). • TheBLOB (binary large object) data type is used to store large binary objects in the database in line (inside the row) or out of line (outside the row).

• TheBFILE (binary file) data type is used to store large binary objects in operating system files outside the database. • TheNCLOB (national language character large object) data type is used to store large blocks of single-byte or fixed-width multibyte NCHAR unicode data in the database, in line or out of line. Bind variables can be used to pass run-time values, either number or character, into or out of one or more PL/SQL programs. VARIABLE RESULT NUMBER BEGIN SELECT (SALARY*12) + NVL(COMMISSION_PCT,0) INTO :RESULT FROM employees WHERE employee_id = 144; END; / PRINT RESULT use the PRINT command. However, PRINT cannot be used inside a PL/SQL block because it is an iSQL*Plus Host variables are also called bind variables.
If verify is on, SQL*Plus prints two lines for each substituted variable (see set define.

VARIABLE g_monthly_sal NUMBER DEFINE p_annual_sal = 50000 SET VERIFY OFF DECLARE v_sal NUMBER(9,2) := &p_annual_sal; BEGIN :g_monthly_sal := v_sal/12; END; / PRINT g_monthly_sal SET SERVEROUTPUT ON DEFINE p_annual_sal = 60000 DECLARE v_sal NUMBER(9,2) := &p_annual_sal; BEGIN v_sal := v_sal/12; DBMS_OUTPUT.PUT_LINE ('The monthly salary is ' || TO_CHAR(v_sal)); END; Variables declared in an external environment such as iSQL*Plus are called host variables. Comment-Prefix single-line comments with two dashes (--). • Place multiple-line comments between the symbols /* and */. CHR is the SQL function that converts an ASCII code to its corresponding character; 10 is the code for a line feed. IF x > y THEN v_max := x; ELSE v_max := y; END IF; v_salary NUMBER(8,2) := &p_salary; Enter value for p_salary: 4000 old 2: v_salary NUMBER(8,2) := &p_salary;

e. . 'Cores'. 4000). location_id INTO v_deptno. or DROP TABLE. salary) VALUES (employees_seq. or SAVEPOINT command. such as CREATE TABLE. 'AD_ASST'. ROLLBACK. This area is called a cursor. such as GRANT or REVOKE. Whenever you issue a SQL statement. c. The decision whether to update or insert into the target table is based on a condition in the ON clause. • TheDELETE statement removes unwanted rows from the table.first_name. first_name.e. • TheUPDATE statement modifies existing rows in the table.last_name = e. The programmer explicitly declares and names an explicit cursor. SELECT department_id. INSERT INTO employees (employee_id.email.department_id). hire_date.employee_id. .email = e. Control a transaction with the COMMIT.last_name. job_id. There are four attributes available in PL/SQL that can be applied to cursors. MERGE INTO copy_emp c USING employees e ON (e.first_name = e. • TheMERGE statement selects rows from one table to update or insert into another table..employee_id = v_empno) WHEN MATCHED THEN UPDATE SET c. c. email. sysdate.first_name. UPDATE employees SET salary = salary + v_sal_increase WHERE job_id = 'ST_CLERK'. which PL/SQL manages automatically.NEXTVAL. . . • PL/SQL does not directly support data definition language (DDL) statements.2) := 4000.new 2: v_salary NUMBER(8. 'RCORES'. WHEN NOT MATCHED THEN INSERT VALUES(e. • Explicit cursors are explicitly declared by the . e. • PL/SQL does not support data control language (DCL) statements. A cursor is a private SQL work area. • There are two types of cursors: – Implicit cursors – Explicit cursors • The Oracle server uses implicit cursors to parse and execute your SQL statements. ALTER TABLE.. the Oracle server opens an area of memory in which the command is parsed and executed. PL/SQL creates an implicit cursor.last_name. 'Ruth'. DELETE FROM employees WHERE department_id = v_deptno. v_location_id FROM departments Queries Must Return One and Only One Row NO_DATA_FOUND and TOO_MANY_ROWS DML • TheINSERT statement adds new rows of data to the table. When the executable part of a block issues a SQL statement. last_name..

country_id) VALUES((v_location_id + v_counter). v_country_id )..programmer. IF condition THEN statements. END. WHEN expressionN THEN resultN [ELSE resultN+1. city. v_counter := v_counter + 1. . v_city. END LOOP. v_country_id). END LOOP. / PRINT rows_deleted SAVEPOINT savepoint_name. ROLLBACK [WORK] TO [SAVEPOINT] savepoint_name. :rows_deleted := (SQL%ROWCOUNT ||' row deleted. SQL%NOTFOUND. country_id) VALUES((v_location_id + v_counter). and SQL%ISOPEN in the exception section %BULK_ROWCOUNT.. country_id) VALUES((v_location_id + i). ROLLBACK [WORK]. v_counter := v_counter + 1.3 LOOP INSERT INTO locations(location_id. END LOOP. You can use the attributes SQL%ROWCOUNT. EXIT WHEN v_counter > 3.. v_country_id). city. [ELSIF condition THEN statements. CASE selector WHEN expression1 THEN result1 WHEN expression2 THEN result2 .] [ELSE statements.v_city. FOR i IN 1. SQL%FOUND.'). that is not covered in this course. designed for use with the FORALL statement. There are three loop types: • Basic loop that perform repetitive actions without overall conditions • FOR loops that perform iterative control of actions based on a count • WHILE loops that perform iterative control of actions based on a condition LOOP INSERT INTO locations(location_id.] END IF. v_city. v_appraisal := CASE v_grade WHEN 'A' THEN 'Excellent' WHEN 'B' THEN 'Very Good' WHEN 'C' THEN 'Good' ELSE 'No such grade' END.] END. city. WHILE v_counter <= 3 LOOP INSERT INTO locations(location_id.

• Use the WHILE loop if the condition has to be evaluated at the start of each iteration. You use the IF construct to perform a conditional execution of statements. so the primary key value can be negative. A record that contains such fields as the name. a record is declared using %ROWTYPE as a data type specifier. such as name. salary. TYPE emp_record_type IS RECORD (last_name VARCHAR2(25).. The magnitude range of a BINARY_INTEGER is -2147483647 . This data is dissimilar in type but logically related. hire date. The following methods make INDEX BY tables easier to use: – NEXT – TRIM – DELETE – EXISTS – COUNT – FIRST and LAST .. DECLARE emp_record employees%ROWTYPE. which stores the INDEX BY table elements TYPE ename_table_type IS TABLE OF employees.and so on. • Use a FOR loop if the number of iterations is known.A conditional control construct checks for the validity of a condition and performs a corresponding action accordingly. each with its own name and data type. An iterative control construct executes a sequence of statements repeatedly. Index By table – A primary key of data type BINARY_INTEGER that indexes the INDEX BY table – A column of a scalar or record data type. Indexing does not need to start with 1. 2147483647. as long as a specified condition holds TRUE. You use the various loop constructs to perform iterative operations. Composite Data Type Are of two types: – PL/SQL RECORDs – PL/SQL Collections – INDEX BY Table – Nested Table – VARRAY • Contain internal components • Are reusable A record is a group of related data items stored as fields.2)). Use the basic loop when the statements inside the loop must execute at least once.last_name%TYPE INDEX BY BINARY_INTEGER. job_id VARCHAR2(10). and hire date of an employee allows you to treat the data as a logical unit. emp_record emp_record_type. salary. A table contains a column and a primary key to give you array-like access to rows. salary NUMBER(8. Record-suppose you have different kinds of data about an employee.

CLOSE emp_cursor. Parameter to Cursor DECLARE CURSOR emp_cursor (p_deptno NUMBER. but you can extend it to 8. but nested tables have an extensible upper bound. The CLOSE statement disables the cursor. . which you must specify in its type definition. 9.. For example.. To reference an element. the size of a nested table can be extended VARRAYS?????????????????? Items of the VARRAY type are called VARRAYS. you use standard subscripting syntax. END LOOP. nested tables differ from arrays because arrays have a fixed upper bound. However. A VARRAY has a maximum size. you should not commit across fetches from an explicit cursor if FOR UPDATE is used. last_name FROM employees WHERE department_id = p_deptno AND job_id = p_job. BEGIN OPEN emp_cursor (80. OPEN emp_cursor (60. . 'SA_REP'). Thus a VARRAY can contain a varying number of elements. Explicit Cursor You use the OPEN. and positions the cursor before the first row. last_name FROM employees. . The FOR UPDATE Clause You may want to lock rows before you update or delete rows.. v_ename. This association enables you manipulate the collection as a whole and to reference individual elements easily.– PRIOR Nested Tables Within the database.. They allow you to associate a single identifier with an entire collection. emp_record emp_cursor%ROWTYPE. CLOSE emp_cursor. Because the Oracle Server releases locks at the end of the transaction. The FETCH statement retrieves the current row and advances the cursor to the next row until either there are no more rows or until the specified condition is met. GRADES(3) references the third element in VARRAY grades. DECLARE CURSOR emp_cursor IS SELECT employee_id. Its index has a fixed lower bound of 1 and an extensible upper bound. END. FETCH. p_job VARCHAR2) IS SELECT employee_id. and CLOSE statements to control a cursor. for example. NOWAIT returns an Oracle error if the rows are locked by another session . Add the FOR UPDATE clause in the cursor query to lock the affected rows when the cursor is opened.10 LOOP FETCH emp_cursor INTO v_empno. OPEN emp_cursor FOR i IN 1.. Thus. from zero (when empty) to the maximum specified in its type definition. nested tables can be considered one-column database tables. Close the cursor when the last row has been processed. The OPEN statement executes the query associated with the cursor. or 10.. identifies the result set. END. the current upper bound for VARRAY grades is 7.. 'IT_PROG').

use the WHERE CURRENT OF clause. then locks each row in the result set. The optional NOWAIT keyword tells Oracle not to wait if requested rows have been locked by another user.The SELECT . This allows you to apply updates and deletes to the row currently being addressed. Trapping an Exception If the exception is raised in the executable section of the block. You must include the FOR UPDATE clause in the cursor query so that the rows are locked on OPEN. Propagating an Exception If the exception is raised in the executable section of the block and there is no corresponding exception handler. any other exceptions are not trapped unless you use the OTHERS exception handler.department_id = e. departments d WHERE d.salary * 1. last_name. then the exception does not propagate to the enclosing block or environment. Subqueries are often used in the WHERE clause of a select statement. the cursor will close. WHEN OTHERS Exception Handler Predefined Oracle Server error Do not declare and allow the Oracle server to raise them implicitly Nonpredefined Oracle Server error Declare within the declarative section and allow the Oracle Server to raise them implicitly User-defined error Declare within the declarative section.department_id. the PL/SQL block terminates with failure and the exception is propagated to the calling environment. When evaluated. If you omit the NOWAIT keyword . the subquery provides a value or set of values to the outer query. This is useful when you want to base an update on the existing values in a row. Exception You raise an exception explicitly by issuing the RAISE statement within the block. They can also be used in the FROM clause. . The exception being raised may be either user-defined or predefined. Oracle waits until the rows are available. Cursors with Subqueries A subquery is a query (usually enclosed by parentheses) that appears within another SQL data manipulation statement.salary < 5000 THEN UPDATE employees SET salary = emp_record. If you do a COMMIT before closing the cursor.. BEGIN FOR emp_record IN sal_cursor LOOP IF emp_record. without the need to explicitly reference the ROWID.department_id and d.department_id = 60 FOR UPDATE OF salary NOWAIT. This traps any exception not yet handled. employee_id. END IF. salary FROM employees e. processing branches to the corresponding exception handler in the exception section of the block. Control is immediately returned to your program so that it can do other work before trying again to acquire the lock. If PL/SQL successfully handles the exception. you must make sure the row is not changed by another user before the update. CURSOR sal_cursor IS SELECT e. END LOOP.10 WHERE CURRENT OF sal_cursor.. and raise explicitly The exception-handling section traps only those exceptions that are specified. creating a temporary data source for that query. The PL/SQL block terminates successfully. In that case. FOR UPDATE statement identifies the rows that will be updated or deleted. The WHERE CURRENT OF Clause When referencing the current row from an explicit cursor.

extensibility. the PRAGMA EXCEPTION_INIT tells the compiler to associate an exception name with an Oracle error number. e_emps_remaining EXCEPTION. IF SQL%NOTFOUND THEN RAISE e_invalid_department. Use the RAISE_APPLICATION_ERROR procedure to communicate a predefined exception interactively by returning a nonstandard error code and error message. Definition of a Procedure A procedure is a named PL/SQL block that can accept parameters (sometimes referred to as . or by using the OTHERS handler.user defined 0-no exception Trapping User-Defined Exceptions PL/SQL allows you to define your own exceptions. '). COMMIT. It provides modularity. {TRUE | FALSE}]). BEGIN DELETE FROM departments WHERE department_id = &p_deptno.For this reason. Employees exist. EXCEPTION WHEN e_invalid_department THEN DBMS_OUTPUT.PUT_LINE('No such department id. That That allows you to refer to any internal exception by name and to write a specific handler for it. User-defined PL/SQL exceptions must be: • Declared in the declare section of a PL/SQL block • Raised explicitly with RAISE statements DECLARE e_invalid_department EXCEPTION.'). END IF. COMMIT. Trapping Nonpredefined Oracle Server Errors You trap a nonpredefined Oracle server error by declaring it first. OTHERS is the last exception handler that is defined. A subprogram is based on standard PL/SQL structure that contains a declarative section.) SQLERRM Returns character data containing the message associated with the error Number 1.PUT_LINE ('Cannot remove dept ' || TO_CHAR(&p_deptno) || '. A subprogram can be compiled and stored in the database. you can report errors to your application and avoid returning unhandled exceptions. raise_application_error (error_number. With RAISE_APPLICATION_ERROR. and an optional exception-handling section. PRAGMA EXCEPTION_INIT (e_emps_remaining. reusability. END. and maintainability. END. In PL/SQL. message[. -2292). an executable section. BEGIN UPDATE departments SET department_name = '&p_department_desc' WHERE department_id = &p_department_number. Error 2292 integrity constraint violation SQLCODE Returns the numeric value for the error code (You can assign it to a NUMBER variable. EXCEPTION WHEN e_emps_remaining THEN DBMS_OUTPUT.

Formal Versus Actual Parameters Formal parameters are variables declared in the parameter list of a subprogram specification. CREATE OR REPLACE PROCEDURE format_phone (p_phone_no IN OUT VARCHAR2) IS BEGIN p_phone_no := '(' || SUBSTR(p_phone_no.salary%TYPE. / PRINT g_phone_no EXECUTE format_phone (:g_phone_no) PRINT g_phone_no Parameter passing method Positional Lists values in the order in which the parameters are declared . 2000) to the procedure RAISE_SAL. :g_comm) causes a compilation error. :g_name.commission_pct%TYPE) IS BEGIN SELECT last_name. p_comm FROM employees WHERE employee_id = p_id. Generally speaking. A procedure can be compiled and stored in the database as a schema object. raise+100. commission_pct INTO p_name. an executable section.4. p_salary. TheREPLACE option indicates that if the procedure exists. you use a procedure to perform an action. p_name OUT employees.employee_id%TYPE. For example: EXECUTE query_emp(171. in the call raise_sal(v_id . For example.3) || '-' || SUBSTR(p_phone_no. END format_phone. the variables P_ID and P_AMOUNT are formal parameters. :g_sal. salary. in the procedure RAISE_SAL.1. and an optional exceptionhandling section. For example. p_comm OUT employees. :g_comm) PRINT g_name Note: Passing a constant or expression as an actual parameter to the OUT variable causes compilation errors.last_name%TYPE. EXECUTE query_emp(171. a declaration section. END query_emp. Actual parameters are variables or expressions referenced in the parameter list of a subprogram call. A procedure has a header. the variable V_ID and 2000 are actual parameters.arguments). :g_name.3) || ')' || SUBSTR(p_phone_no. p_salary OUT employees. it will be dropped and replaced with the new version created by the statement. VARIABLE g_phone_no VARCHAR2(15) BEGIN :g_phone_no := '8006330575'. and be invoked. IN (default) Passes a constant value from the calling environment into the procedure OUT Passes a value from the procedure to the calling environment IN OUT Passes a value from the calling environment into the procedure and a possibly different value from the procedure back to the calling environment using the same parameter the compiler hint NOCOPY? CREATE OR REPLACE PROCEDURE query_emp (p_id IN employees. END.7). Procedures promote reusability and maintainability.

2500). using special syntax (=>) Combination Lists the first values positionally.. and the remainder using the special syntax of the named method CREATE OR REPLACE PROCEDURE add_dept (p_name IN departments. END leave_emp2.Named association Lists values in arbitrary order by associating each one with its parameter name. add_dept ( p_loc => 1200) CREATE OR REPLACE PROCEDURE leave_emp2 (p_id IN employees. Stored Functions A function is a named PL/SQL block that can accept parameters and be invoked.department_name%TYPE DEFAULT 'unknown'.location_id%TYPE DEFAULT 1700) IS add_dept ('TRAINING'. SYSDATE).. p_loc IN departments. END log_exec.employee_id%TYPE) IS PROCEDURE log_exec IS BEGIN INSERT INTO log_table (user_id. A function must return a value to the calling environment. and an optional exception-handling part.employee_id%TYPE) RETURN NUMBER IS v_salary employees. you use a function to compute a value. BEGIN raise_salary(v_id). a declarative part. a function has a header. Like a procedure. DECLARE v_id NUMBER := 163. --invoke procedure COMMIT. Use SHOW ERRORS to see any compilation errors. A function must have a RETURN clause in the header and at least one RETURN statement in the executable section. Generally speaking. an executable part. END. . Functions and procedures are structured alike. log_date) VALUES (USER. p_name =>'EDUCATION'). .salary%TYPE :=0. BEGIN DELETE FROM employees WHERE employee_id = p_id. log_exec. add_dept ( p_loc => 2400. CREATE OR REPLACE FUNCTION get_sal (p_id IN employees. BEGIN SELECT salary INTO v_salary FROM employees WHERE employee_id = p_id. DROP PROCEDURE raise_salary. whereas a procedure returns zero or more values to its calling environment.

the function cannot modify any database tables. or system control statements (such as ALTER SYSTEM). The same restriction applies to parameters of the function. A procedure can contain zero or more parameters that can be transferred to and from the calling environment. and the value is returned through a RETURN statement. How Procedures and Functions Differ You create a procedure to store a series of actions for later execution. Named notation is not supported. • When called froman UPDATE. RETURN statement in the executable section of the code. following benefits: • Improved performance – Avoid reparsing for multiple users by exploiting the shared SQL area – Avoid PL/SQL parsing at run time by parsing at compile time – Reduce the number of calls to the database and decrease network traffic by bundling commands • Easy maintenance – Modify routines online without interfering with other users – Modify one routine to affect multiple applications – Modify one routine to eliminate duplicate testing • Improved data security and integrity – Control indirect access to database objects from nonprivileged users with security privileges – Ensure that related actions are performed together. or DELETE statement. • You must own or have the EXECUTE privilege on the function to call it from a SQL statement. which must be returned to the calling environment. but a procedure does not have to return a value. • When called froma SELECT. or TABLE. RECORD. • The functions must return data types that are valid SQL data types. CREATE (ANY) PROCEDURE ALTER ANY PROCEDURE DROP ANY PROCEDURE EXECUTE ANY PROCEDURE . or DELETE statement. VARIABLE g_salary NUMBER EXECUTE :g_salary := get_sal(117) PRINT g_salary Restrictions on Calling Functions from SQL Expressions Parameters to a PL/SQL function called from a SQL statement must use positional notation.RETURN v_salary. session control statements (such as SET ROLE). Functions should return only a single value. • The function cannot call another subprogram that breaks one of the above restrictions. Also. You create a function when you want to compute a value. INSERT. it cannot execute DDL statements (such as CREATE) because they are followed by an automatic commit. the function cannot execute SQL transaction control statements (such as COMMIT). When called froma SELECT statement or a parallelized UPDATE or DELETE statement. There can be a RETURN statement in the exception section of the program also. END get_sal. you reduce the need for comments and enhance clarity. • Stored PL/SQL functions cannot be called from the CHECK constraint clause of a CREATE or ALTER TABLE command or be used to specify a default value for a column. They cannot be PL/SQLspecific data types such as BOOLEAN. the function cannot query or modify any database tables modified by that statement. A function can contain zero or more parameters that are transferred from the calling environment. UPDATE. by funneling activity for related tables through a single path • Improved code clarity: By using appropriate identifier names to describe the actions of the routine. or not at all. Functions used in SQL statements cannot have OUT or IN OUT mode parameters.

and then the package body. . Once written and compiled. exceptions. Still. parameterized. END comm_package. constants. 3. variables. SHOW ERRORS [{FUNCTION|PROCEDURE|PACKAGE|PACKAGE BODY|TRIGGER|VIEW} [schema. Package specspackage_name Name the package-public type and item declarations-Declare variables. This enables you to change the definition of a program construct in the package body without causing the Oracle server to invalidate other schema objects that call or reference the program construct. 2. When you call a packaged PL/SQL construct for the first time. the contents can be shared by many applications.Write the text of the CREATE PACKAGE statement within a SQL script file to create the package specification and run the script file. the whole package is loaded into memory. Thus. and subprograms available for use. A package usually has a specification and a body. Private package constructs are those that are defined solely within the package body. and subprograms into one container. The source code is compiled into P code and is stored within the data dictionary. constants. or nested. The package specification may also include PRAGMAs. 1. Write the text of the CREATE PACKAGE BODY statement within a SQL script file to create the package body and run the script file.]name] The DBMS_OUTPUT package: – Accumulates information into a buffer – Allows retrieval of the information from the buffer • Autonomous procedure calls (for example. The body fully defines cursors and subprograms. cursors. The specification is the interface to your applications. Obtaining Compile Errors To obtain the text for compile errors. Invoke any public construct within the package from an Oracle server environment. It declares the types. cursors. exceptions. --initialized to 0. The source code is compiled into P code and is also stored within the data dictionary.10 PROCEDURE reset_comm (p_comm IN NUMBER). later calls to constructs in the same package require no disk input/output (I/O). items. use the USER_SOURCE data dictionary view. Public package constructs are those that are declared in the package specification and defined in the package body. text FROM user_errors WHERE name = 'LOG_EXECUTION' ORDER BY line. the format of a package is similar to that of a subprogram.Using USER_SOURCE To obtain the text of a stored procedure or function. stored separately in the database. which are directives to the compiler. or types subprogram specifications-Declare the PL/SQL subprograms CREATE OR REPLACE PACKAGE comm_package IS g_comm NUMBER := 0. The Oracle server stores the specification and body of a package separately in the database. CREATE OR REPLACE PROCEDURE log_execution SELECT line || '/' || position POS. Package Development You create a package in two parts: first the package specification.10. and so implements the specification. The package itself cannot be called. use the USER_ERRORS data dictionary view or the SHOW ERRORS iSQL*Plus command. writing the output to a log table) • Software that uses DBMS_DEBUG – Procedure Builder – Third-party debugging software Packages Overview Packages bundle related PL/SQL types.

depending on whether the construct is private or public. / EXECUTE DBMS_OUTPUT. Example 4 Call the RESET_COMM procedure that is located in a remote database that is determined by the database link named NY from iSQL*Plus. cursors. exceptions. exceptions. making the prevailing commission 0.0936.10. package_name Is the name of the package private type and item declarations Declares variables. meter_2_yard CONSTANT NUMBER := 1. constants.6093. These are not visible outside the package body.15 for the user session. • The REPLACE option drops and recreates the package body. Invoking Package Constructs After the package is stored in the database. CREATE [OR REPLACE] PACKAGE BODY package_name IS|AS private type and item declarations subprogram bodies END package_name. Declaring a Bodiless Package You can create a package specification that does not need a package body. or types subprogram bodies Defines the PL/SQL subprograms. and call specifications. • RESET_COMM is a public procedure that is implemented in the package body. kilo_2_mile CONSTANT NUMBER := 0. you can invoke a package construct within the package or from outside the package. Example 2 Call the RESET_COMM procedure from iSQL*Plus. public and private When you are coding the package body. CREATE OR REPLACE PACKAGE global_consts IS mile_2_kilo CONSTANT NUMBER := 1. As discussed earlier in this lesson. • All private constructs must be declared before they are used in the public constructs.15 for the user session.PUT_LINE('20 miles = '||20* global_consts.6214. constants. you must qualify its name with the name of the package. • Identifiers defined only in the package body are private constructs./ • G_COMM is a global variable and is initialized to 0. Example 3 Call the RESET_COMM procedure that is located in the SCOTT schema from iSQL*Plus. making the prevailing commission 0.mile_2_kilo||' km') Referencing a Public Variable from . you do not need to qualify its name. When you invoke a package procedure or function from within the same package. variables. END global_consts. When you invoke a package procedure or function from outside the package.9144. the definition of the private function has to be above the definition of the public procedure.15 for the user session. yard_2_meter CONSTANT NUMBER := 0. making the prevailing commission 0. if a specification declares only types. the package body is unnecessary.

and they offer several benefits. Hiding Information You can decide which constructs are public (visible and accessible) or private (hidden and inaccessible). by hiding implementation details from users. This way. END meter_to_yard. use the following syntax: To remove the package body. / VARIABLE yard NUMBER EXECUTE meter_to_yard (1.a Stand-Alone Procedure Example: CREATE OR REPLACE PROCEDURE meter_to_yard (p_meter IN NUMBER. Packaged subprograms also stop cascading dependencies and so avoid unnecessary compilation. clear. and well defined. Modularity You encapsulate logically related programming structures in a named module. :yard) PRINT yard To remove the package specification and the body. Each package is easy to understand. Only the declarations in the package specification are visible and accessible to applications. Better Performance When you call a packaged subprogram the first time. This enables you to change the implementation without having to recompile calling programs. Easier Application Design All you need initially is the interface information in the package specification.meter_2_yard. Then stored subprograms that reference the package can compile as well. You can code and compile a specification without its body. you protect the integrity of the package. The package body hides the definition of the private constructs so that only the package is affected (not your application or any calling programs) if the definition changes. They also enable you to maintain data across transactions without having to store it in the database. and the interface between packages is simple. which means you can create multiple subprograms with the same name in the same package. Place items in the declaration part of the package body when you must maintain them throughout a session or across transactions Advantages of Using Packages Packages provide an alternative to creating procedures and functions as stand-alone schema objects. Also. Thus. Overloading With packages you can overload procedures and functions. p_yard OUT NUMBER) IS BEGIN p_yard := p_meter * global_consts. the entire package is loaded into memory. Overloading This feature enables you to define different subprograms with the same name. later calls to related subprograms in the package require no further disk I/O. Added Functionality Packaged public variables and cursors persist for the duration of a session. but can only be accessed within the package. Private constructs also persist for the duration of the session. each taking parameters of different number or datatype. The package specification should contain only those constructs that you want to be public. Removing Packages DROP PACKAGE BODY package_name. Sometimes the processing in two subprograms is the . You can distinguish the subprograms both by name and by parameters. they can be shared by all subprograms that execute in the environment. You need not define the package body fully until you are ready to complete the application. use the following syntax: DROP PACKAGE package_name.

You can use forward declarations to do the following: • Define subprograms in logical or alphabetical order • Define mutually recursive subprograms • Group subprograms in a package CREATE OR REPLACE PACKAGE BODY forward_pack IS PROCEDURE calc_rating(.p(x => 4) For example. • If you redeclare a built-in subprogram in a PL/SQL program. but the parameters passed to them varies. column 7: PLS-00307: too many declarations of 'P' match this call ORA-06550: line 1. / EXECUTE overload. procedure p ( n number). invoke the procedure with named notation: EXECUTE overload. FUNCTION TO_CHAR (p1 NUMBER. -. Restrictions You cannot overload: • Two subprograms if their formal parameters differ only in data type and the different data types are in the same family (NUMBER and DECIMAL belong to the same family) • Two subprograms if their formal parameters differ only in subtype and the different subtypes are based on types in the same family (VARCHAR and STRING are PL/SQL subtypes of VARCHAR2) • Two functions that differ only in return type. It consists of the subprogram specification terminated by a semicolon.forward declaration PROCEDURE award_bonus(. * ERROR at line 1: ORA-06550: line 1.p(4).) IS -.subprograms defined BEGIN -. Therefore. FUNCTION TO_CHAR (p1 DATE. CREATE OR REPLACE PACKAGE overload IS procedure p (x number). then you can invoke the subprograms by using named notation for the parameters. . END. If you use different names for the parameters. PL/SQL enables for a special subprogram declaration called a forward declaration. You can overload two subprograms if their formal parameters differ only in name or parameter mode. PL/SQL determines which subprogram is called by checking its formal parameters. Only local or packaged subprograms can be overloaded. a subprogram must be declared before calling it.same. Stand-alone subprograms cannot be overloaded. . END. your local declaration overrides the global declaration.in alphabetical order .p(4) overload. see the TO_CHAR function of the STANDARD package. FUNCTION TO_CHAR (p1 DATE) RETURN VARCHAR2. column 7: PL/SQL: Statement ignored Now. FUNCTION TO_CHAR (p2 NUMBER) RETURN VARCHAR2. P2 VARCHAR2) RETURN VARCHAR2. even if the types are in different families You get a run-time error when you overload subprograms with the above features. Using Forward Declarations PL/SQL does not allow forward references.). . . In that case it is logical to give them the same name. Note: The above restrictions apply if the names of the parameters are also the same. P2 VARCHAR2) RETURN VARCHAR2. You must declare an identifier before using it.

. Dynamic SQL statements are not embedded in your source program but rather are stored in character strings that are input to. the operations are performed . you can use DBMS_SQL or native dynamic SQL. Therefore. END. you use dynamic SQL to create a procedure that operates on a table whose name is not known until run time..). . That is.sql….. this is used for functionality such as objects and collections. In PL/SQL.calc_rating(. FETCH. you can write stored procedures and anonymous PL/SQL blocks that use dynamic SQL. you have to use DBMS_SQL to write dynamic SQL. you use OPEN-FOR. END. Some of the procedures and functions of the package include: – OPEN_CURSOR – PARSE – BIND_VARIABLE – EXECUTE – FETCH_ROWS – CLOSE_CURSOR Using the DBMS_SQL Package Using DBMS_SQL. PROCEDURE calc_rating(. DBMS_SQL can issue data definition language statements in PL/SQL. the program. or to write and execute a data definition language (DDL) statement (such as CREATE TABLE). if the caller is an anonymous PL/SQL block. which are not supported by DBMS_SQL. In Oracle8. The EXECUTE IMMEDIATE statement can perform dynamic single-row queries. a data control statement (such as GRANT). and earlier. SQL statements go through various stages: • Parse • Bind • Execute • Fetch Using the DBMS_SQL Package The DBMS_SQL package is used to write dynamic SQL in stored procedures and to parse DDL statements.. For example.) IS BEGIN . . For example. the SQL statements can be created dynamically at run time by using variables. and CLOSE statements. PRAGMA RESTRICT_REFERENCES ??????????????? Describe the use and application of some Oracle server-supplied packages: – DBMS_DDL – DBMS_JOB – DBMS_OUTPUT – UTL_FILE – UTL_HTTP and UTL_TCP Write dynamic SQL statements using DBMS_SQL and EXECUTE IMMEDIATE Most of the standard packages are created by running catproc. such statements cannot be executed statically. or built by. In Oracle 8i. If the statement is a multirow SELECT statement. . or a session control statement (such as ALTER SESSION). . The operations provided by this package are performed under the current user.sys schema Using Native Dynamic SQL (Dynamic SQL) You can write PL/SQL blocks that use dynamic SQL. END forward_pack. not under the package owner SYS.. you can choose to issue a DROP TABLE statement from within a stored procedure. Also..

:deleted) PRINT deleted Execute Immediate Use the EXECUTE IMMEDIATE statement for native dynamic SQL with better performance. FETCH. but you must use OPEN-FOR. DBMS_SQL CREATE OR REPLACE PROCEDURE delete_all_rows (p_tab_name IN VARCHAR2. DBMS_SQL. EXECUTE IMMEDIATE dynamic_string [INTO {define_variable [. END. and CLOSE for a multirow query. BEGIN cursor_name := DBMS_SQL. define_variable] . dynamic_string A string expression that represents a dynamic SQL statement (without terminator) or a PL/SQL block (with terminator) define_variable A variable that stores the selected column value record A user-defined or %ROWTYPE record that stores a selected row bind_argument An expression whose value is passed to the dynamic SQL statement or PL/SQL block You can use the INTO clause for a single-row query. . It is used only for single-row queries.CLOSE_CURSOR(cursor_name). p_rows_del := DBMS_SQL.PARSE(cursor_name. if the caller is a stored procedure. The default parameter mode is IN. there must be a corresponding. 'DELETE FROM '||p_tab_name. ].OPEN_CURSOR. p_rows_del OUT NUMBER) IS cursor_name INTEGER. • USING is used to hold all bind arguments. p_rows_deld OUT NUMBER) IS BEGIN EXECUTE IMMEDIATE 'delete from '||p_table_name. • INTO is used for single-row queries and specifies the variables or records into which column values are retrieved. CREATE PROCEDURE del_rows (p_table_name IN VARCHAR2.. Use dynamic SQL to delete rows VARIABLE deleted NUMBER EXECUTE delete_all_rows('employees'...NATIVE ). DBMS_SQL. SELECT text FROM all_source WHERE name ='DBMS_SQL' ORDER BY LINE. p_rows_deld := SQL%ROWCOUNT. DBMS_SQL..according to the privileges of the current user. [IN|OUT|IN OUT] bind_argument] . The most likely reason for this is that the package is being used to drop a procedure that you are still using. the operations are performed according to the owner of the stored procedure. | record}] [USING [IN|OUT|IN OUT] bind_argument [. Using this package to execute DDL statements can result in a deadlock. In the EXECUTE IMMEDIATE statement: • TheINTO clause specifies the variables or record into which column values are retrieved. type-compatible variable or field in the INTO clause. For each value retrieved by the query. The EXECUTE IMMEDIATE statement prepares (parses) and immediately executes the dynamic SQL statement. END.EXECUTE (cursor_name).

It is used only for DML statements that have a RETURNING clause (without a BULK COLLECT clause). the USING clause can contain only IN arguments. DBMS_DDL. If you use both the USING clause and the RETURNING INTO clause. or trigger.ANALYZE_OBJECT.ALTER_COMPILE('PROCEDURE'. package.'QUERY_EMP') DBMS_DDL. using DBMS_UTILITY.ANALYZE_OBJECT('TABLE'. For each value returned by the DML statement. object_name) – ANALYZE_OBJECT (object_type. • TheUSING clause holds all bind arguments. or DELETE. function. CLUSTER.'A_USER'. (There is a way of analyzing more than one object at a time. owner. package body. method) Note: This package runs with the privileges of calling user.'A_USER'. is OUT. rather than the package owner SYS. For DML statements that have a RETURNING clause. the time at which the job will be run. name. which.• TheRETURNING INTO clause specifies the variables into which column values are returned. • You can analyze a single object. by definition.) The object type should be TABLE. or the interval between executions of the job) WHAT Alters the job description for a specified job . Using the DBMS_DDL Package The DBMS_DDL Package: • Provides access to some SQL DDL statements from stored procedures • Includes some procedures: – ALTER_COMPILE (object_type. The method must be COMPUTE. you can place OUT arguments in the RETURNING INTO clause without specifying the parameter mode. Using DBMS_JOB for Scheduling DBMS_JOB Enables the scheduling and execution of PL/SQL programs: • Submitting jobs • Executing jobs • Changing execution parameters of jobs • Removing jobs • Suspending Jobs DBMS_JOB Subprograms Available subprograms include: • SUBMIT • REMOVE • CHANGE • WHAT • NEXT_DATE • INTERVAL • BROKEN • RUN DBMS_JOB Subprograms Subprogram Description SUBMIT Submits a job to the job queue REMOVE Removes a specified job from the job queue CHANGE Alters a specified job that has already been submitted to the job queue (you can alter the job description. or INDEX. type-compatible variable in the RETURNING INTO clause. The object type must be either procedure. • This package gives developers access to ALTER and ANALYZE SQL statements through PL/SQL environments. using DBMS_DDL. ESTIMATE.'JOBS'. owner.'COMPUTE') Practical Uses • You can recompile your modified PL/SQL program units by using DBMS_DDL. there must be a corresponding.ALTER_COMPILE. The default parameter mode is IN.

PUT_LINE. Available procedures include: • PUT • NEW_LINE • PUT_LINE • GET_LINE • GET_LINES • ENABLE/DISABLE PUT Appends text from the procedure to the current line of the line output buffer NEW_LINE Places an end_of_line marker in the output buffer PUT_LINE Combines the action of PUT and NEW_LINE GET_LINE Retrieves the current line from the output buffer into the procedure GET_LINES Retrieves an array of lines from the output buffer into the procedure ENABLE/DISABLE Enables or disables calls to the DBMS_OUTPUT procedures UTL_FILE Oracle-supplied package: – Provides text file I/O capabilities – Is available with version 7. the Oracle server does not attempt to execute it) RUN Forces a specified job to run DBMS_JOB. next_date => TRUNC(SYSDATE + 1). what => 'OVER_PACK.ADD_DEPT(''EDUCATION''.'.SUBMIT ( job => :jobno. Function or Procedure Description .3 and later • The DBMS_LOB Oracle-supplied package: – Provides read-only operations on external BFILES – Is available with version 8 and later – Enables read and write operations on internal LOBs Is similar to standard operating system I/O – Open files – Get text – Put text – Close files – Use the exceptions specific to the UTL_FILE package UTL_FILE Procedures and Functions • Function FOPEN • Function IS_OPEN • Procedure GET_LINE • Procedure PUT. FCLOSE_ALL The UTL_FILE Package: Procedures and Functions Note: The maximum size of an input record is 1.NEXT_DATE Alters the next execution time for a specified job INTERVAL Alters the interval between executions for a specified job BROKEN Disables job execution (if a job is marked as broken. PUTF • Procedure NEW_LINE • Procedure FFLUSH • Procedure FCLOSE.2710).023 bytes unless you specify a larger size in the overloaded version of FOPEN. interval => 'TRUNC(SYSDATE + 1)' Using the DBMS_OUTPUT Package The DBMS_OUTPUT package enables you to output messages from PL/SQL blocks.

You can use it to access data on the Internet or to call Oracle Web Server Cartridges. The UTL_HTTP package makes hypertext transfer protocol (HTTP) callouts from PL/SQL and SQL.' EMPLOYEE: %s earns: %s\n'. UTL_FILE.PUTF (v_filehandle.FOPEN A function that opens a file for input or output and returns a file handle used in subsequent I/O operations IS_OPEN A function that returns a Boolean value whenever a file handle refers to an open file GET_LINE A procedure that reads a line of text from the opened file and places the text in the output buffer parameter (the maximum size of an input record is 1.023 bytes unless you specify a larger size in the overloaded version of FOPEN) PUT. v_emp_rec. which is set to 50 by default. use new_line to terminate the line. Guidelines for Creating Directory Objects To associate an operating system file to a BFILE.PUT_LINE (v_filehandle.last_name. PUT_LINE A procedure that writes a text string stored in the buffer parameter to the opened file (no line terminator is appended by put. END IF. The Oracle server allows up to 32 triggers to cascade at any one time. By coupling UTL_HTTP with the DBMS_JOBS package.department_id). 'Unable to write to file'). Because many Internet application protocols are based on TCP/IP. \n is a new line character) NEW_LINE Procedure that terminates a line in an output file FFLUSH Procedure that writes all data buffered in memory to a file FCLOSE Procedure that closes an opened file FCLOSE_ALL Procedure that closes all opened file handles for the session IF v_newdeptno <> v_olddeptno THEN UTL_FILE. or use PUT_LINE to write a complete line with a terminator) PUTF A formatted put procedure with two format specifiers: %s and \n (use %s to substitute a value into the output string. 'DEPARTMENT: %s\n'.PUTF (v_filehandle. Trigger timing When the trigger fires in relation to the triggering event BEFORE AFTER . WHEN UTL_FILE. UTL_FILE.INVALID_FILEHANDLE THEN RAISE_APPLICATION_ERROR (-20001. '*** END OF REPORT ***'). you can easily schedule reoccurring requests be made from your database server out to theWeb. this package is useful to PL/SQL applications that use Internet protocols. Using the UTL_TCP Package The UTL_TCP package enables PL/SQL applications to communicate with external TCP/IP-based servers using TCP/IP. Recursive trigger: This is a trigger that contains a DML operation changing the very same table. v_emp_rec. UTL_FILE. • Cascading trigger: The action of one trigger cascades to another trigger. EXCEPTION WHEN UTL_FILE. 'Invalid File. you should first create a DIRECTORY object that is an alias for the full pathname to the operating system file. The UTL_HTTP Package UTL_HTTP is a package that allows you to make HTTP requests directly from the database.salary). the number of cascading triggers can be limited by changing the value of the OPEN_CURSORS database initialization parameter.WRITE_ERROR THEN RAISE_APPLICATION_ERROR (-20002.FCLOSE (v_filehandle). causing this second trigger to fire.'). END LOOP. v_olddeptno := v_newdeptno. v_emp_rec. However.

END IF.').'You may update EMPLOYEES table only during normal hours.'SUN')) OR (TO_CHAR (SYSDATE.'SUN')) OR (TO_CHAR(SYSDATE. If the triggering event affects no rows. END IF. 'HH24') NOT BETWEEN '08' AND '18') THEN IF DELETING THEN RAISE_APPLICATION_ERROR (-20502. This is used for views that are not otherwise modifiable. ELSIF UPDATING ('SALARY') THEN RAISE_APPLICATION_ERROR (-20503. ELSE RAISE_APPLICATION_ERROR (-20504. Statement triggers are useful if the trigger action does not depend on the data from rows that are affected or on data provided by the triggering event itself: for example. CREATE OR REPLACE TRIGGER secure_emp BEFORE INSERT OR UPDATE OR DELETE ON employees BEGIN IF (TO_CHAR (SYSDATE.'). Row triggers are useful if the trigger action depends on data of rows that are affected or on data provided by the triggering event itself. even if no rows are affected at all.').INSTEAD OF Triggering event Which data manipulation operation on the table or view causes the trigger to fire INSERT UPDATE DELETE Trigger type How many times the trigger bodyexecutes StatementRow Trigger body What action the trigger performs Complete PL/SQL block Trigger timing: When should the trigger fire? • BEFORE: Execute the trigger body before the triggering DML event on a table. CREATE OR REPLACE TRIGGER secure_emp BEFORE INSERT ON employees BEGIN IF (TO_CHAR(SYSDATE.'You may delete from EMPLOYEES table only during business hours.'You may insert into EMPLOYEES table only during business hours.'You may insert into EMPLOYEES table only during business hours. Row Trigger A row trigger fires each time the table is affected by the triggering event. a row trigger is not executed.'DY') IN ('SAT'.'DY') IN ('SAT'. Trigger type: Should the trigger body execute for each row the statement affects or only once? Statement Trigger A statement trigger is fired once on behalf of the triggering event.'HH24:MI') NOT BETWEEN '08:00' AND '18:00') THEN RAISE_APPLICATION_ERROR (-20500. • AFTER: Execute the trigger body after the triggering DML event on a table. ELSIF INSERTING THEN RAISE_APPLICATION_ERROR (-20500. .'). END.'You may update SALARY only during business hours. a trigger that performs a complex security check on the current user. • INSTEAD OF: Execute the trigger body instead of the triggering statement.').

UPDATE new_depts SET tot_dept_sal = tot_dept_sal .salary WHERE department_id = :NEW. group functions. SYSDATE). :NEW. :OLD. or joins. :NEW.department_id. START. new_title. 'AD_VP')) AND :NEW. For example. CREATE OR REPLACE TRIGGER restrict_salary BEFORE INSERT OR UPDATE OF salary ON employees FOR EACH ROW BEGIN IF NOT (:NEW. the trigger body executes.set_g_ins(1).email. clauses such as GROUP BY. old_title. timestamp. you write an INSTEAD OF trigger that fires when you write an insert against the view.last_name. which results in an insertion of data into one table and an update to another table CREATE OR REPLACE TRIGGER new_emp_dept INSTEAD OF INSERT OR UPDATE OR DELETE ON emp_details FOR EACH ROW BEGIN IF INSERTING THEN INSERT INTO new_emps VALUES (:NEW.employee_id. :NEW.last_name.job_id. END. old_salary. CREATE OR REPLACE TRIGGER audit_emp_values AFTER DELETE OR INSERT OR UPDATE ON employees FOR EACH ROW BEGIN INSERT INTO audit_emp_table (user_name.salary > 15000 THEN RAISE_APPLICATION_ERROR (-20202. Why Use INSTEAD OF Triggers? A view cannot be modified by normal DML statements if the view query contains set operators.set_g_del(1). ALTER TRIGGER trigger_name COMPILE CREATE OR REPLACE TRIGGER audit_emp_trig AFTER UPDATE or INSERT or DELETE on EMPLOYEES FOR EACH ROW BEGIN IF DELETING THEN var_pack. :NEW.last_name. Instead of the original insertion.salary. old_last_name. new_salary) VALUES (USER.employee_id. new_last_name. :NEW. UPDATE new_depts SET tot_dept_sal = tot_dept_sal + :NEW. END.salary WHERE department_id = :OLD.'Employee cannot earn this amount'). :New.department_id.department_id.job_id. an insert to the view may entail an insertion into one table and an update to another. the DISTINCT operator.salary.END IF. :OLD. CONNECT BY. ELSIF UPDATING ('SALARY') . ELSIF DELETING THEN DELETE FROM new_emps WHERE employee_id = :OLD.:OLD. :OLD. id. END.job_id. SYSDATE. :NEW. :NEW. So.salary ). ELSIF INSERTING THEN var_pack. END IF. if a view consists of more than one table. :OLD.employee_id.job_id IN ('AD_PRES'.

Cursor Variables • Cursor variables are like C or Pascal pointers. -. dept_cv DeptCurTyp. • You can pass the value of a cursor variable freely from one scope to another. you OPEN a cursor variable FOR a multirow query. executes the query. where REF is short for REFERENCE and X stands for a class of objects • A cursor variable has the data type REF CURSOR • A cursor is static. FETCH. UPDATE.2)).declare cursor variable Using the OPEN-FOR.THEN var_pack. but a cursor variable is dynamic • Cursor variables give you more flexibility Why Use Cursor Variables? • You can use cursor variables to pass query result sets between PL/SQL stored subprograms and various clients. • PL/SQL can share a pointer to the query work area in which the result set is stored. END IF. and CLOSE. TYPE EmpCurTyp IS REF CURSOR RETURN employees%ROWTYPE.set_g_up_sal(1). emp_cv EmpCurTyp. -. you FETCH rows from the result set one at a time. . you CLOSE the cursor variable. • Example: DECLARE TYPE DeptCurTyp IS REF CURSOR RETURN departments%ROWTYPE.strong TYPE GenericCurTyp IS REF CURSOR.weak TYPE EmpRecTyp IS RECORD ( empno NUMBER(4). ref_cv ref_type_name. First. -. TYPE EmpCurTyp IS REF CURSOR RETURN EmpRecTyp.set_g_upd(1). • You can reduce network traffic by having a PL/SQL block open (or close) several host cursor variables in a single round trip. ELSE var_pack. a pointer is declared as REF X. ename VARCHAR2(1O). and CLOSE Statements You use three statements to process a dynamic multirow query: OPEN-FOR. • Declare a cursor variable of that type. When all the rows are processed. Then. Opening the Cursor Variable The OPEN-FOR statement associates a cursor variable with a multirow query. Define a REF CURSOR type. FETCH. END audit_emp_trig. Define a REF CURSOR type TYPE ref_type_name IS REF CURSOR [RETURN return_type]. AUDIT INSERT. which hold the memory location (address) of an item instead of the item itself • In PL/SQL. sal NUMBER(7. DELETE ON departments BY ACCESS WHENEVER SUCCESSFUL.

EmpCurTyp. bind_argument]. DECLARE TYPE EmpCurTyp IS REF CURSOR. of the type EmpcurTyp. First you must define a REF CURSOR type... a pointer to the IN actual parameter is passed to the corresponding formal parameter. By default. then sets the rows-processed count kept by %ROWCOUNT to zero. DECLARE TYPE EmpCurTyp IS REF CURSOR.. .open cursor variable 'SELECT last_name. if the subprogram exits normally. CLOSE emp_cv. both parameters reference the same memory location. At run time. END. the IN parameter is passed by reference. positions the cursor to point to the first row of the results set. NOCOPY Compiler Hint Suppose a subprogram declares an IN parameter.identifies the result set. the values assigned to the . -. / An Example of Fetching The example in the preceding slide shows that you can fetch rows from the result set of a dynamic multirow query into a record. That is. the OUT and IN OUT parameters are passed by value. LOOP FETCH emp_cv INTO emp_rec. the value of the IN OUT actual parameter is copied into the corresponding formal parameter. and an IN OUT parameter. sql_stmt VARCHAR2(200). When the last row is processed. the OPEN-FOR statement associates the cursor variable EMP_CV with the multirow query. bind arguments in the USING clause replace corresponding placeholders in the dynamic SELECT statement. salary FROM employees WHERE salary > :s' USING my_sal. -. Then. The FETCH statement returns a row from the result set of a multirow query and assigns the values of select-list items to EMP_REC in the INTO clause. the dynamic form has an optional USING clause.define weak REF CURSOR type emp_cv EmpCurTyp. That is. my_sal NUMBER := 1000.]. Unlike the static form of OPEN-FOR. sql_stmt. close the cursor variable EMP_CV. END.process record END LOOP. -. emp_cv EmpCurTyp. emp_rec employees%ROWTYPE. an OUT parameter.. In the executable section of the PL/SQL block. The syntax is: OPEN {cursor_variable | :host_cursor_variable} FOR dynamic_string [USING bind_argument[. Next you define a cursor variable emp_cv. So. which holds the value of the actual parameter. my_job VARCHAR2(10) := 'ST_CLERK'. When you call the subprogram. BEGIN sql_stmt := 'SELECT * FROM employees WHERE job_id = :j'. BEGIN OPEN emp_cv FOR -. OPEN emp_cv FOR sql_stmt USING my_job. EXIT WHEN emp_cv%NOTFOUND.declare cursor variable my_ename VARCHAR2(15).

you ask the compiler to pass IN OUT parameter my_staff by reference instead of by value: OUT DECLARE TYPE Staff IS VARRAY(200) OF Employee. performance suffers. So. So. it can benefit any PL/SQL application that passes around large data structures. As Figure 4-3 shows. NOCOPY succeeds. When the parameters hold large data structures such as collections. which allows the PL/SQL compiler to pass OUT and IN OUT parameters by reference. the PL/SQL engine accepts any valid PL/SQL block or subprogram. all of the same type (for example. For example. That can happen when SQL statements execute inside a loop using collection (index-by table. not a directive. Remember. Collection A collection is an ordered group of elements. all this copying slows down execution and uses up memory. Figure 4-3 Context Switching Each context switch between the PL/SQL and SQL engines adds to overhead. To prevent that. order.. returns data to the PL/SQL engine. and instances of object types. the PL/SQL engine executes procedural statements but sends SQL statements to the SQL engine.and IN OUT formal parameters are copied into the corresponding actual parameters. the compiler might pass my_staff by value despite your request. or host array) elements as bind variables. Usually. if many switches are required. PROCEDURE reorganize (my_staff IN OUT NOCOPY Staff) IS . you can use the same name for several different subprograms as long as their formal parameters differ in number. in some cases. you can specify the NOCOPY hint. records. Overloading PL/SQL lets you overload subprogram names. varray. However. or datatype family. the grades for a class of students) Collections work like the arrays found in most third-generation programming languages. which executes the SQL statements and. That is. collections can have only one dimension and must be indexed by integers Taking Advantage of Bulk Binds Embedded in the Oracle RDBMS. the following DELETE statement is sent to the SQL engine with each iteration of the FOR loop: DECLARE . nested table. So.. In the following example. NOCOPY is a hint. however.

6 t1 CHAR(5). For example. In such cases. with an entire nested table: DECLARE TYPE NumList IS TABLE OF NUMBER. 30. pnames(i))...load index-by tables 13 pnums(j) := j.. 21 FORALL i IN 1. FORALL i IN mgrs. the following DELETE statement is sent to the SQL engine just once.. SQL> SET SERVEROUTPUT ON SQL> CREATE TABLE parts (pnum NUMBER(4). First.depts.manager numbers BEGIN .use FOR loop 18 INSERT INTO parts VALUES (pnums(i). they are bulk-inserted using a FORALL statement.LAST LOOP . 7 t2 CHAR(5). 7782.5000 LOOP -.. if the SQL statement affects five or more database rows. 17 FOR i IN 1. END.). which completes in 38 seconds.5000 LOOP -. The binding of an entire collection at once is called bulk binding. -. all table elements are inserted into a database table twice. In the example below. FOR i IN depts.). .mgrs. pnames(i)).. which completes in only 3 seconds. 8 t3 CHAR(5). the use of bulk binds can improve performance considerably. DELETE FROM emp WHERE deptno = depts(i). 5 pnames NameTab...5000 -. . entire collections. ' || TO_CHAR(j). Then.FIRST. . Table created. 5000 part numbers and names are loaded into index-by tables. END... depts NumList := NumList(10. Bulk binds improve performance by minimizing the number of context switches between the PL/SQL and SQL engines. 23 get_time(t3).'SSSSS') INTO t FROM dual.sql 1 DECLARE 2 TYPE NumTab IS TABLE OF NUMBER(4) INDEX BY BINARY_INTEGER. 16 get_time(t1). SQL> GET test. 20 get_time(t2). not just individual elements. -.. With bulk binds. pname CHAR(15)).. 11 BEGIN 12 FOR j IN 1..LAST DELETE FROM emp WHERE mgr = mgrs(i).. 15 END LOOP. 14 pnames(j) := 'Part No. Then. are passed back and forth.TYPE NumList IS VARRAY(20) OF NUMBER. How Do Bulk Binds Improve Performance? The assigning of values to PL/SQL variables in SQL statements is called binding. they are inserted using a FOR loop.department numbers BEGIN . END LOOP.FIRST.. END. 3 TYPE NameTab IS TABLE OF CHAR(15) INDEX BY BINARY_INTEGER. 70. mgrs NumList := NumList(7566. 19 END LOOP. 9 PROCEDURE get_time (t OUT NUMBER) IS 10 BEGIN SELECT TO_CHAR(SYSDATE.use FORALL statement 22 INSERT INTO parts VALUES (pnums(i). 4 pnums NumTab.

. BEGIN depts.raises an "element does not exist" exception END..mgrs.fill varray here . 25 DBMS_OUTPUT. BEGIN -. END. 40). Although the FORALL statement contains an iteration scheme. FORALL j IN 6. However.20 INSERT INTO emp2 VALUES (enums(i). UPDATE.10 -. depts NumList := NumList(10.... To bulk-bind input collections.FIRST. -. As the following example shows. use the BULK COLLECT clause.FIRST.upper_bound sql_statement. in the following example. The SQL engine executes the SQL statement once for each index number in the range. it is not a FOR loop. 20.illegal subscript All collection elements in the specified range must exist. If an element is missing or was deleted. .. The SQL statement can reference more than one collection. And. names(i). the bounds must specify a valid range of consecutive index numbers. The SQL statement must be an INSERT.LAST DELETE FROM emp WHERE mgr = mgrs(j+1). 27 DBMS_OUTPUT.DELETE(3). -. 30.depts.LAST DELETE FROM emp WHERE deptno = depts(i). . Using the FORALL Statement The keyword FORALL instructs the PL/SQL engine to bulk-bind input collections before sending them to the SQL engine. SQL> / Execution Time (secs) --------------------FOR loop: 38 FORALL: 3 PL/SQL procedure successfully completed. depts NumList := NumList().PUT_LINE('FORALL: ' || TO_CHAR(t3 .PUT_LINE('Execution Time (secs)').t1)). use the FORALL statement. median(sals). Its syntax follows: FORALL index IN lower_bound. So. you get an error.. which is passed to the function median: FORALL i IN 1. 28* END.delete third element FORALL i IN depts. The index can be referenced only within the FORALL statement and only as a collection subscript. -. as the following example shows: DECLARE TYPE NumList IS TABLE OF NUMBER. To bulk-bind output collections. or DELETE statement that references collection elements. you can use the bounds to bulk-bind arbitrary slices of a collection: DECLARE TYPE NumList IS VARRAY(15) OF NUMBER. The next example shows that the collection subscript cannot be an expression: FORALL j IN mgrs.PUT_LINE('FOR loop: ' || TO_CHAR(t2 . it does not bulk-bind the collection sals.24 DBMS_OUTPUT.bulk-bind middle third of varray UPDATE emp SET sal = sal * 1.. 26 DBMS_OUTPUT.PUT_LINE('---------------------'). the PL/SQL engine bulk-binds only subscripted collections.t2)).).10 WHERE deptno = depts(j)..

. -. the engine loads 50. and RETURNING INTO clauses.LAST UPDATE emp2 SET job = job || ' (temp)' WHERE deptno = depts(j). INSERT INTO emp2 VALUES(30.. starting at index 1. only the second execution is rolled back. 'Bookkeeper').. ename BULK COLLECT INTO enums. The first execution succeeds. In the following example. The SQL engine bulk-binds entire database columns.. once for each index number in the specified range.. FETCH INTO. you try to append the 7-character string ' (temp)' to certain job titles using the following UPDATE statement: DECLARE TYPE NumList IS TABLE OF NUMBER.ename%TYPE.raises a "value too large" exception EXCEPTION WHEN OTHERS THEN COMMIT. BEGIN SELECT empno.empno%TYPE.) Then. -. you insert some rows into the table. However. So. Here is the syntax: . as follows: INSERT INTO emp2 VALUES(10. The SQL engine executes the UPDATE statement twice. names FROM emp. if a table has 50. Then. job VARCHAR2(15)).10-char job title INSERT INTO emp2 VALUES(30. once for depts(10) and once for depts(20). it cannot extend varrays beyond their maximum size. 'Clerk'). -. You can use these keywords in the SELECT INTO. it inserts elements consecutively and overwrites any preexistent elements.. 'Analyst'). In this case. Using the BULK COLLECT Clause The keywords BULK COLLECT tell the SQL engine to bulk-bind output collections before returning them to the PL/SQL engine. you can use the pseudocolumn ROWNUM to limit the number of rows processed. The SQL engine bulk-binds all collections referenced in the INTO list.no need to initialize names NameTab. 20). END.000 rows.. you limit the number of rows to 100: DECLARE . (However. that is.FIRST. Next. collection_name] .Rollback Behavior If a FORALL statement fails.depts. END. Changes made during previous executions are not rolled back. BULK COLLECT INTO collection_name[. enums NumTab. 'Clerk'). INSERT INTO emp2 VALUES(10. In the following example. The SQL engine initializes and extends collections for you. The corresponding columns must store scalar (not composite) values. depts NumList := NumList(10. suppose you create a database table that stores department numbers and job titles. For example. database changes are rolled back to an implicit savepoint marked before each execution of the SQL statement. 'Analyst'). TYPE NameTab IS TABLE OF emp. BEGIN FORALL j IN depts. but the second execution fails because the string value 'Bookkeeper (temp)' is too large for the job column. INSERT INTO emp2 VALUES(20. as follows: CREATE TABLE emp2 (deptno NUMBER(2). the SQL engine loads the entire empno and ename database columns into nested tables before returning the tables to the PL/SQL engine: DECLARE TYPE NumTab IS TABLE OF emp. .000 column values into the target collection.

At run time.illegal .ename%TYPE.LAST DELETE FROM emp WHERE empno = depts(j) RETURNING empno BULK COLLECT INTO enums. (With a FOR loop.assume that values were assigned to the host array . Using FORALL and BULK COLLECT Together You can combine the BULK COLLECT clause with a FORALL statement. . as the following example shows: DECLARE TYPE EmpRecTab IS TABLE OF emp%ROWTYPE. the anonymous PL/SQL block is sent to the database server for execution.... Host arrays are declared in a host environment such as an OCI or Pro*C program and must be prefixed with a colon to distinguish them from PL/SQL collections. BEGIN -. Bulk Fetching The following example shows that you can bulk-fetch from a cursor into one or more collections: DECLARE TYPE NameTab IS TABLE OF emp. sals SalTab. In the following example. the previous values are overwritten.depts. in which case. BEGIN OPEN c1.. CURSOR c1 IS SELECT ename. END. .empno%TYPE. END.. emp_recs EmpRecTab.. BULK COLLECT statement in a FORALL statement. sals NumTab. The column values returned by each execution are added to the values returned previously. if collection depts has 3 elements. FETCH c1 BULK COLLECT INTO names. CURSOR c1 IS SELECT ename. that is the most efficient way to pass collections to and from the database server. Using Host Arrays Client-side programs can use anonymous PL/SQL blocks to bulk-bind input and output host arrays.sal%TYPE. names NameTab. Restriction: You cannot bulk-fetch from a cursor into a collection of records. TYPE SalTab IS TABLE OF emp... In the example below. then collection enums has 15 elements when the statement completes: FORALL j IN depts.FIRST.TYPE NumTab IS TABLE OF emp.. BEGIN OPEN c1. END. sals. each of which causes 5 rows to be deleted.) Restriction: You cannot use the SELECT . sal FROM emp WHERE sal > 1000. DECLARE . an input host array is used in a DELETE statement. FETCH c1 BULK COLLECT INTO emp_recs. the SQL engine bulk-binds column values incrementally. BEGIN SELECT sal BULK COLLECT INTO sals FROM emp WHERE ROWNUM <= 100. In fact.. sal FROM emp WHERE sal > 1000. -..

If the ith execution affects no rows.. You can define RECORD types in the declarative part of any PL/SQL block. %NOTFOUND.10 WHERE deptno = depts(j). Restrictions: %BULK_ROWCOUNT cannot be assigned to other collections. each with its own name and datatype. These items are logically related but dissimilar in type. Note: Only index-by tables can have negative subscripts. The datatype RECORD lifts those restrictions and lets you define your own records. %FOUND and %NOTFOUND refer only to the last execution of the SQL statement. END IF END.. You cannot use collection methods such as FIRST and LAST with host arrays.and host variables in the host environment FORALL i IN :lower. depts NumList := NumList(10.10. An example follows: DECLARE TYPE NumList IS TABLE OF NUMBER. respectively.. %ISOPEN. However. %BULK_ROWCOUNT.).FIRST. and hire date. which has the semantics of an index-by table. so does %BULK_ROWCOUNT. then declare records of that type. %BULK_ROWCOUNT and the FORALL statement use the same subscripts. or package using the syntax TYPE type_name IS RECORD (field_declaration[.:upper DELETE FROM emp WHERE deptno = :depts(i).. you can use %BULK_ROWCOUNT to infer their values for individual executions. records make it easier to organize and represent information. %NOTFOUND. The SQL cursor has only one composite attribute. 50). you cannot specify the datatypes of fields in the record or declare fields of your own. This cursor's attributes (%FOUND.FIRST. when %BULK_ROWCOUNT(i) is zero.LAST -. you define a RECORD type.depts..LAST UPDATE emp SET sal = sal * 1. However. A record containing a field for each item lets you treat the data as a logical unit. You can also use the scalar attributes %FOUND. it cannot be passed as a parameter to subprograms. Its ith element stores the number of rows processed by the ith execution of a SQL statement. if the FORALL statement uses the range -5. . For example. where field_declaration stands for field_name field_type [[NOT NULL] {:= | DEFAULT} expression] . and %ROWCOUNT) return useful information about the most recently executed SQL data manipulation statement. Also. For instance. 20. Using Cursor Attributes To process SQL data manipulation statements. What Is a Record? A record is a group of related data items stored in fields.. For example. Defining and Declaring Records To create records. %BULK_ROWCOUNT(i) returns zero.field_declaration].-. BEGIN FORALL j IN depts..:depts. The attribute %ROWTYPE lets you declare a record that represents a row in a database table. and %ROWCOUNT with bulk binds. %ROWCOUNT returns the total number of rows processed by all executions of the SQL statement. For example.. the SQL engine opens an implicit cursor named SQL.illegal DELETE FROM emp WHERE deptno = :depts(i). the following statement is illegal: FORALL i IN :depts.. %FOUND and %NOTFOUND are FALSE and TRUE. IF SQL%BULK_ROWCOUNT(3) = 0 THEN . Suppose you have various data about an employee such as name. END. Thus.. salary. subprogram.

2)). So.declare record The identifier item_info represents an entire record.2)). As the example below shows. salary NUMBER(7. Each field has a unique name and specific datatype. FUNCTION nth_highest_salary (n INTEGER) RETURN EmpRec IS . -. salary REAL(7. dept_num INTEGER(2). object types cannot have attributes of type RECORD. TYPE FlightRec IS RECORD ( flight_no INTEGER. Declaring Records Once you define a RECORD type. the value of a record is actually a collection of values.declare object passengers PassengerList. Notice that field declarations are like variable declarations. description VARCHAR2(50).. you can declare records of that type. PL/SQL lets you define records that contain objects. as the following example shows: DECLARE TYPE StockItem IS RECORD ( item_no INTEGER(3). and other records (called nested records). DECLARE TYPE TimeRec IS RECORD ( seconds SMALLINT. minutes SMALLINT. field_type is any PL/SQL datatype except REF CURSOR. plane_id VARCHAR2(10). -. you define a RECORD type named DeptRec: DECLARE TYPE DeptRec IS RECORD ( dept_id dept.and where type_name is a type specifier used later to declare records. That allows the function to return a user-defined record of the same type. -. dept_name VARCHAR2(15).. user-defined records can be declared as the formal parameters of procedures and functions. quantity INTEGER. captain Employee. dept_loc VARCHAR2(15)). Note: Unlike TABLE and VARRAY types. job_title VARCHAR2(15). . collections. You can use %TYPE and %ROWTYPE to specify field types. However. job_title VARCHAR2(15).deptno%TYPE. The next example shows that you can specify a RECORD type in the RETURN clause of a function specification. In the following example. . price REAL(7. Like scalar variables.empno%TYPE.. RECORD types cannot be CREATEd and stored in the database. DECLARE TYPE EmpRec IS RECORD ( emp_id INTEGER last_name VARCHAR2(15). hours SMALLINT). -. each of some simpler type.declare varray depart_time TimeRec. An example follows: DECLARE TYPE EmpRec IS RECORD ( emp_id emp.declare nested record airport_code VARCHAR2(10)). last_name VARCHAR2(10). item_info StckItem.2)). and expression yields a value of the same type as field_type..

The next example shows that you can impose the NOT NULL constraint on any field. PROCEDURE raise_salary (emp_info EmpRec). mins SMALLINT := 0. DECLARE TYPE TimeRec IS RECORD ( secs SMALLINT := 0. Initializing and Referencing Records The example below shows that you can initialize a record in its type definition... DECLARE TYPE StockItem IS RECORD ( item_no INTEGER(3) NOT NULL := 999. its three fields assume an initial value of zero.. When you declare a record of type TimeRec. hrs SMALLINT := 0). Fields declared as NOT NULL must be initialized. . and so prevent the assigning of nulls to that field.

Sign up to vote on this title
UsefulNot useful