Application Developer's Guide - Fundamentals
Application Developer's Guide - Fundamentals
Release 2 (9.2)
Oracle9i Application Developers Guide - Fundamentals, Release 2 (9.2) Part No. A96590-01 Copyright 1996, 2002 Oracle Corporation. All rights reserved. Primary Author: John Russell T. Brooksfuller, T. Burroughs, M. Cowan, J. Levinger, R. Moran, R. Strohm
Contributing Authors:
Contributors: D. Alpern, G. Arora, C. Barclay, D. Bronnikov, T. Chang, M. Davidson, G. Doherty, D. Elson, A. Ganesh, M. Hartstein, J. Huang, N. Jain, R. Jenkins Jr., S. Kotsovolos, S. Kumar, C. Lei, D. Lorentz, R. Murthy, R. Pang, B. Sinha, S. Vemuri, W. Wang, D. Wong, A. Yalamanchi, Q. Yu Graphic Designer: V. Moore The Programs (which include both the software and documentation) contain proprietary information of Oracle Corporation; they are provided under a license agreement containing restrictions on use and disclosure and are also protected by copyright, patent and other intellectual and industrial property laws. Reverse engineering, disassembly or decompilation of the Programs, except to the extent required to obtain interoperability with other independently created software or as specied by law, is prohibited. The information contained in this document is subject to change without notice. If you nd any problems in the documentation, please report them to us in writing. Oracle Corporation does not warrant that this document is error-free. Except as may be expressly permitted in your license agreement for these Programs, no part of these Programs may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without the express written permission of Oracle Corporation. If the Programs are delivered to the U.S. Government or anyone licensing or using the programs on behalf of the U.S. Government, the following notice is applicable: Restricted Rights Notice Programs delivered subject to the DOD FAR Supplement are "commercial computer software" and use, duplication, and disclosure of the Programs, including documentation, shall be subject to the licensing restrictions set forth in the applicable Oracle license agreement. Otherwise, Programs delivered subject to the Federal Acquisition Regulations are "restricted computer software" and use, duplication, and disclosure of the Programs shall be subject to the restrictions in FAR 52.227-19, Commercial Computer Software - Restricted Rights (June, 1987). Oracle Corporation, 500 Oracle Parkway, Redwood City, CA 94065. The Programs are not intended for use in any nuclear, aviation, mass transit, medical, or other inherently dangerous applications. It shall be the licensee's responsibility to take all appropriate fail-safe, backup, redundancy, and other measures to ensure the safe use of such applications if the Programs are used for such purposes, and Oracle Corporation disclaims liability for any damages caused by such use of the Programs. Oracle is a registered trademark, and ConText, Oracle Store, Oracle7, Oracle8, Oracle8i, Oracle9i, PL/SQL, Pro*COBOL, Pro*C, Pro*C/C++, SQL*Net, and SQL*Plus are trademarks or registered trademarks of Oracle Corporation. Other names may be trademarks of their respective owners.
Contents
Send Us Your Comments ................................................................................................................ xvii Preface.......................................................................................................................................................... xix Whats New in Application Development? .......................................................................... xxix 1 Understanding the Oracle Programmatic Environments
Overview of Developing an Oracle Application.......................................................................... Overview of PL/SQL .......................................................................................................................... A Simple PL/SQL Example ........................................................................................................ Advantages of PL/SQL ............................................................................................................... Overview of Java Stored Procedures, JDBC, and SQLJ .............................................................. Overview of Writing Procedures and Functions in Java ....................................................... Overview of Oracle JDBC............................................................................................................ Overview of Oracle SQLJ................................................................................................................ SQLJ Tool ..................................................................................................................................... Benefits of SQLJ .......................................................................................................................... Comparing SQLJ with JDBC ..................................................................................................... SQLJ Example for Object Types ............................................................................................... SQLJ Stored Procedures in the Server ..................................................................................... Programming with J2EE, OC4J, SOAP, JAAS, Servlets, JSPs, EJBs, CORBA, and UDDI .. Overview of Pro*C/C++................................................................................................................... How You Implement a Pro*C/C++ Application................................................................... Highlights of Pro*C/C++ Features .......................................................................................... 1-2 1-3 1-4 1-4 1-8 1-8 1-9 1-14 1-14 1-15 1-15 1-17 1-20 1-20 1-21 1-21 1-23
iii
Overview of Pro*COBOL ................................................................................................................ How You Implement a Pro*COBOL Application .................................................................. Highlights of Pro*COBOL Features ......................................................................................... Overview of OCI and OCCI ........................................................................................................... Advantages of OCI ..................................................................................................................... Parts of the OCI ........................................................................................................................... Procedural and Non-Procedural Elements ............................................................................. Building an OCI Application .................................................................................................... Overview of Oracle Objects for OLE (OO4O)............................................................................. OO4O Automation Server ......................................................................................................... OO4O Object Model ................................................................................................................... Support for Oracle LOB and Object Datatypes ...................................................................... The Oracle Data Control ............................................................................................................ The Oracle Objects for OLE C++ Class Library...................................................................... Additional Sources of Information........................................................................................... Choosing a Programming Environment....................................................................................... Choosing Whether to Use OCI or a Precompiler ................................................................... Using Built-In Packages and Libraries..................................................................................... Java versus PL/SQL ...................................................................................................................
1-24 1-24 1-26 1-26 1-27 1-28 1-28 1-29 1-31 1-32 1-32 1-37 1-39 1-39 1-39 1-40 1-40 1-41 1-42
iv
About Key-Preserved Tables ................................................................................................... Rule for DML Statements on Join Views ................................................................................ Using the UPDATABLE_COLUMNS Views.......................................................................... Outer Joins .................................................................................................................................. Managing Sequences ....................................................................................................................... Creating Sequences ................................................................................................................... Altering Sequences .................................................................................................................... Using Sequences ......................................................................................................................... Dropping Sequences ................................................................................................................. Managing Synonyms ....................................................................................................................... Creating Synonyms ................................................................................................................... Using Synonyms in DML Statements ..................................................................................... Dropping Synonyms ................................................................................................................. Creating Multiple Tables and Views in One Operation .......................................................... Naming Schema Objects ................................................................................................................. Rules for Name Resolution in SQL Statements ..................................................................... Renaming Schema Objects ............................................................................................................ Switching to a Different Schema................................................................................................... Listing Information about Schema Objects.................................................................................
2-16 2-17 2-20 2-20 2-23 2-23 2-24 2-24 2-28 2-28 2-29 2-29 2-30 2-30 2-31 2-32 2-33 2-34 2-34
Selecting a Datatype
Summary of Oracle Built-In Datatypes.......................................................................................... Representing Character Data.......................................................................................................... Representing Numeric Data ........................................................................................................... Representing Date and Time Data ................................................................................................ Date Format ................................................................................................................................. Time Format ................................................................................................................................ Establishing Year 2000 Compliance ......................................................................................... Representing Geographic Coordinate Data ................................................................................ Representing Image, Audio, and Video Data.............................................................................. Representing Searchable Text Data............................................................................................... Representing Large Data Types ..................................................................................................... Migrating LONG Datatypes to LOB Datatypes ..................................................................... Using RAW and LONG RAW Datatypes ............................................................................... Addressing Rows Directly with the ROWID Datatype ............................................................ 3-2 3-10 3-13 3-14 3-15 3-16 3-19 3-27 3-27 3-27 3-27 3-28 3-32 3-33
ANSI/ISO, DB2, and SQL/DS Datatypes .................................................................................... How Oracle Converts Datatypes ................................................................................................... Datatype Conversion During Assignments............................................................................ Datatype Conversion During Expression Evaluation ........................................................... Representing Dynamically Typed Data ....................................................................................... Representing XML Data ..................................................................................................................
vi
Privileges Required to Create Constraints ............................................................................. Naming Integrity Constraints .................................................................................................. Enabling and Disabling Integrity Constraints ........................................................................... Enabling and Disabling Existing Integrity Constraints ........................................................ Guidelines for Enabling and Disabling Key Integrity Constraints ..................................... Fixing Constraint Exceptions ................................................................................................... Altering Integrity Constraints........................................................................................................ Renaming Integrity Constraints ............................................................................................... Dropping Integrity Constraints ..................................................................................................... Managing FOREIGN KEY Integrity Constraints ...................................................................... Rules for FOREIGN KEY Integrity Constraints .................................................................... Restriction on Enabling FOREIGN KEY Integrity Constraints ........................................... Viewing Denitions of Integrity Constraints ............................................................................ Examples of Defining Integrity Constraints ...........................................................................
4-19 4-20 4-20 4-22 4-23 4-24 4-24 4-25 4-26 4-27 4-27 4-29 4-29 4-29
vii
Identifying Extensions to SQL92 (FIPS Flagging) ................................................................... Grouping Operations into Transactions......................................................................................... Improving Transaction Performance ......................................................................................... Committing Transactions ........................................................................................................... Rolling Back Transactions .......................................................................................................... Defining Transaction Savepoints ............................................................................................... Privileges Required for Transaction Management .................................................................. Ensuring Repeatable Reads with Read-Only Transactions ....................................................... Using Cursors within Applications ................................................................................................ Declaring and Opening Cursors ................................................................................................ Using a Cursor to Execute Statements Again ........................................................................... Closing Cursors .......................................................................................................................... Cancelling Cursors .................................................................................................................... Locking Data Explicitly .................................................................................................................. Choosing a Locking Strategy ................................................................................................... Letting Oracle Control Table Locking ..................................................................................... Summary of Nondefault Locking Options ............................................................................. Explicitly Acquiring Row Locks .............................................................................................. About User Locks.............................................................................................................................. When to Use User Locks............................................................................................................ Example of a User Lock ............................................................................................................. Viewing and Monitoring Locks ................................................................................................ Using Serializable Transactions for Concurrency Control ...................................................... How Serializable Transactions Interact ................................................................................... Setting the Isolation Level of a Transaction ............................................................................ Referential Integrity and Serializable Transactions ............................................................... READ COMMITTED and SERIALIZABLE Isolation ............................................................ Application Tips for Transactions ............................................................................................ Autonomous Transactions............................................................................................................... Examples of Autonomous Transactions.................................................................................. Defining Autonomous Transactions........................................................................................ Resuming Execution After a Storage Error Condition............................................................... What Operations Can Be Resumed After an Error Condition? ........................................... Limitations on Resuming Operations After an Error Condition ......................................... Writing an Application to Handle Suspended Storage Allocation .....................................
7-2 7-4 7-4 7-5 7-6 7-6 7-7 7-8 7-9 7-9 7-9 7-10 7-10 7-11 7-12 7-15 7-16 7-17 7-18 7-18 7-19 7-20 7-20 7-24 7-24 7-25 7-27 7-30 7-31 7-34 7-39 7-40 7-40 7-40 7-40
viii
Example of Resumable Storage Allocation............................................................................. Querying Data at a Point in Time (Flashback Query) ............................................................... Setting Up the Database for Flashback Query ....................................................................... Writing an Application that Uses Flashback Query.............................................................. Flashback Query Restrictions ................................................................................................... Tips for Using Flashback Query...............................................................................................
ix
Timestamps.................................................................................................................................. Signatures .................................................................................................................................... Controlling Remote Dependencies ......................................................................................... Cursor Variables ............................................................................................................................... Declaring and Opening Cursor Variables .............................................................................. Examples of Cursor Variables................................................................................................... Handling PL/SQL Compile-Time Errors ...................................................................................... Handling Run-Time PL/SQL Errors .............................................................................................. Declaring Exceptions and Exception Handling Routines .................................................... Unhandled Exceptions .............................................................................................................. Handling Errors in Distributed Queries ................................................................................. Handling Errors in Remote Procedures ................................................................................. Debugging Stored Procedures........................................................................................................ Calling Stored Procedures............................................................................................................... Calling Remote Procedures ............................................................................................................ Synonyms for Procedures and Packages ................................................................................ Calling Stored Functions from SQL Expressions ....................................................................... Using PL/SQL Functions ......................................................................................................... Syntax for SQL Calling a PL/SQL Function ........................................................................... Naming Conventions ................................................................................................................. Requirements for Calling PL/SQL Functions from SQL Expressions................................ Controlling Side Effects ............................................................................................................. Overloading Packaged PL/SQL Functions............................................................................. Serially Reusable PL/SQL Packages........................................................................................ Returning Large Amounts of Data from a Function .................................................................. Coding Your Own Aggregate Functions.......................................................................................
9-22 9-24 9-29 9-31 9-32 9-32 9-34 9-36 9-37 9-39 9-40 9-40 9-41 9-43 9-47 9-50 9-50 9-50 9-51 9-51 9-54 9-55 9-63 9-64 9-70 9-72
10
The AS LANGUAGE Clause for Java Class Methods........................................................... The AS LANGUAGE Clause for External C Procedures...................................................... Publishing Java Class Methods ................................................................................................... Publishing External C Procedures............................................................................................... Locations of Call Specications ................................................................................................... Passing Parameters to Java Class Methods with Call Specications ................................... Passing Parameters to External C Procedures with Call Specications ............................... Specifying Datatypes................................................................................................................ External Datatype Mappings .................................................................................................. BY VALUE/REFERENCE for IN and IN OUT Parameter Modes.................................... The PARAMETERS Clause ..................................................................................................... Overriding Default Datatype Mapping................................................................................. Specifying Properties ............................................................................................................... Executing External Procedures with the CALL Statement ..................................................... Preliminaries ............................................................................................................................. CALL Statement Syntax........................................................................................................... Calling Java Class Methods..................................................................................................... How the Database Server Calls External C Procedures...................................................... Handling Errors and Exceptions in Multi-Language Programs ............................................ Generic Compile Time Call specification Errors.................................................................. Java Exception Handling ......................................................................................................... C Exception Handling.............................................................................................................. Using Service Procedures with External C Procedures ........................................................... Doing Callbacks with External C Procedures ........................................................................... Object Support for OCI Callbacks .......................................................................................... Restrictions on Callbacks......................................................................................................... Debugging External Procedures............................................................................................. Demo Program.......................................................................................................................... Guidelines for External C Procedures ................................................................................... Restrictions on External C Procedures ..................................................................................
10-9 10-9 10-11 10-12 10-12 10-16 10-16 10-17 10-19 10-21 10-22 10-23 10-23 10-32 10-33 10-34 10-35 10-36 10-37 10-37 10-37 10-37 10-37 10-46 10-48 10-48 10-50 10-50 10-51 10-52
11
xi
Features to Use in Establishing Security Policies................................................................... 11-4 Recommended Application Design Practices to Reduce Risk ............................................. 11-6 Introduction to Application Security Policies.......................................................................... 11-10 Considerations for Using Application-Based Security........................................................ 11-11 Security-Related Tasks of Application Administrators ..................................................... 11-13 Managing Application Privileges........................................................................................... 11-13 Creating Secure Application Roles......................................................................................... 11-14 Associating Privileges with the Users Database Role ....................................................... 11-17 Protecting Database Objects Through Use of Schemas....................................................... 11-20 Managing Object Privileges ................................................................................................... 11-22 Creating a Role and Protecting Its Use .................................................................................. 11-24 Enabling and Disabling Roles ................................................................................................. 11-25 Granting and Revoking System Privileges and Roles ......................................................... 11-30 Granting and Revoking Schema Object Privileges and Roles............................................ 11-32 Granting to, and Revoking from, the User Group PUBLIC .............................................. 11-37
12
xii
Fine-Grained Auditing .................................................................................................................. Introduction to Standard Auditing and Fine-Grained auditing........................................ Standard Oracle9i Auditing Techniques............................................................................... Fine-Grained Auditing Techniques ....................................................................................... Enforcing Application Security ................................................................................................... Use of Ad Hoc Tools a Potential Security Problem ............................................................. Restricting Database Roles from SQL*Plus Users ...............................................................
13
Proxy Authentication
Advantages of Proxy Authentication ............................................................................................ Security Challenges of Three-tier Computing............................................................................ Who Is the Real User? ................................................................................................................ Does the Middle Tier Have Too Much Privilege? ................................................................. How to Audit? Whom to Audit?.............................................................................................. Can the User Be Re-Authenticated to the Database? ............................................................ Oracle9i Proxy Authentication Solutions .................................................................................... Passing Through the Identity of the Real User ...................................................................... Limiting the Privilege of the Middle Tier ............................................................................... Re-authenticating the Real User ............................................................................................... Auditing Actions Taken on Behalf of the Real User............................................................ Support for Application User Models ................................................................................... 13-2 13-3 13-3 13-3 13-4 13-4 13-6 13-6 13-7 13-8 13-10 13-10
14
xiii
Changing Encryption Keys ..................................................................................................... 14-12 Binary Large Objects (BLOBS) ................................................................................................ 14-12 Example of Data Encryption PL/SQL Program ......................................................................... 14-12
15
Using Triggers
Designing Triggers............................................................................................................................ 15-2 Creating Triggers .............................................................................................................................. 15-2 Types of Triggers ........................................................................................................................ 15-3 Naming Triggers ........................................................................................................................ 15-5 When Is the Trigger Fired? ....................................................................................................... 15-5 Controlling When a Trigger Is Fired (BEFORE and AFTER Options) ............................... 15-6 Modifying Complex Views (INSTEAD OF Triggers)............................................................ 15-7 Firing Triggers One or Many Times (FOR EACH ROW Option) ..................................... 15-11 Firing Triggers Based on Conditions (WHEN Clause) ...................................................... 15-12 Coding the Trigger Body .............................................................................................................. 15-13 Accessing Column Values in Row Triggers ......................................................................... 15-16 Triggers and Handling Remote Exceptions ......................................................................... 15-19 Restrictions on Creating Triggers .......................................................................................... 15-21 Who Is the Trigger User? ......................................................................................................... 15-26 Privileges Needed to Work with Triggers ........................................................................... 15-26 Compiling Triggers ........................................................................................................................ 15-27 Dependencies for Triggers ..................................................................................................... 15-27 Recompiling Triggers .............................................................................................................. 15-28 Migration Issues for Triggers ................................................................................................. 15-28 Modifying Triggers ........................................................................................................................ 15-29 Debugging Triggers ................................................................................................................. 15-29 Enabling and Disabling Triggers................................................................................................. 15-29 Enabling Triggers ..................................................................................................................... 15-29 Disabling Triggers ................................................................................................................... 15-30 Viewing Information About Triggers ........................................................................................ 15-30 Examples of Trigger Applications ............................................................................................... 15-32 Responding to System Events through Triggers ...................................................................... 15-52
16
xiv
List of Database Events.................................................................................................................... 16-8 System Events ............................................................................................................................. 16-8 Client Events ............................................................................................................................... 16-9
17
18
19
xv
Is There an Automated Way to Migrate a Schema and Associated Data from Another Database System? 19-2 How Do I Perform Large Numbers of Comparisons within a Query?............................... 19-3 Does Oracle Support Scalar Subqueries? ................................................................................ 19-4
20
Index
xvi
Oracle Corporation welcomes your comments and suggestions on the quality and usefulness of this document. Your input is an important part of the information used for revision.
s s s s s
Did you nd any errors? Is the information clearly presented? Do you need more information? If so, where? Are the examples correct? Do you need more examples? What features did you like most?
If you nd any errors or have any other suggestions for improvement, please indicate the document title and part number, and the chapter, section, and page number (if available). You can send comments to us in the following ways:
s s s
Electronic mail: [email protected] FAX: (650) 506-7227 Attn: Server Technologies Documentation Manager Postal service: Oracle Corporation Server Technologies Documentation 500 Oracle Parkway, Mailstop 4op11 Redwood Shores, CA 94065 USA
If you would like a reply, please give your name, address, telephone number, and (optionally) electronic mail address. If you have problems with the software, please contact your local Oracle Support Services.
xvii
xviii
Preface
The Oracle9i Application Developers Guide - Fundamentals describes features of application development for the Oracle9i Database. Information in this guide applies to features that work the same on all platforms, and does not include system-specic information. This preface contains these topics:
s
Audience
The Oracle9i Application Developers Guide - Fundamentals is intended for programmers developing new applications or converting existing applications to run in the Oracle environment. This book will also be valuable to systems analysts, project managers, and others interested in the development of database applications. This guide assumes that you have a working knowledge of application programming, and that you are familiar with the use of Structured Query Language (SQL) to access information in relational database systems. Certain sections of this guide also assume a knowledge of the basic concepts of object-oriented programming.
xix
Programming in SQL. Your primary source of information for this is the Oracle9i SQL Reference. You can nd information about advanced query techniques, to perform analysis and retrieve data in a single query, in the Oracle9i Data Warehousing Guide. Interfacing to SQL through other languages, such as PL/SQL, Java, or C/C++. Sources of information about these other languages include:
s
PL/SQL Users Guide and Reference Oracle9i Supplied PL/SQL Packages and Types Reference Oracle9i Java Developers Guide Pro*C/C++ Precompiler Programmers Guide Oracle Call Interface Programmers Guide and Oracle C++ Call Interface Programmers Guide Oracle Objects for OLE C++ Class Library Oracle COM Automation Feature Developers Guide
Setting up interactions and mappings between multiple language environments, as described in "Calling External Procedures" on page 10-1. Working with schema objects. You might designing part or all of a schema, and write code to t into an existing schema. You can get an overview in "Managing Schema Objects" on page 2-1, and full details in Oracle9i Database Administrators Guide. Interfacing with the database administrator to make sure that the schema can be backed up and restored, for example after a system failure or when moving between a staging machine and a production machine. Building application logic into the database itself, in the form of stored procedures, constraints, and triggers, to allow multiple applications to reuse application logic and code that checks and cleans up errors. For information on these database features, see "Using Procedures and Packages" on page 9-1, "Maintaining Data Integrity Through Constraints" on page 4-1, and "Using Triggers" on page 15-1. Some degree of performance tuning. The database administrator might help here. You can nd more information in PL/SQL Users Guide and Reference,
xx
Oracle9i Supplied PL/SQL Packages and Types Reference, and Oracle9i Database Performance Tuning Guide and Reference.
s
Some amount of database administration, if you need to maintain your own development or test system. You can learn about administration in the Oracle9i Database Administrators Guide. Debugging and interpreting error messages, which are listed in Oracle9i Database Error Messages. Making your application available over the network, particularly over the Internet or company intranet. You can get an overview in "Developing Web Applications with PL/SQL" on page 18-1, and full details covering various languages and technologies in the Oracle9iAS documentation. Building in security features to prevent tampering or unauthorized access to data. As a developer, you will use the information in "Application Security" on page -1. If you have broader responsibility for database security, you should read Oracle9i Security Overview. Designing the class structure and choosing object-oriented methodologies, if your application is object-oriented. For more information, see Oracle9i Application Developers Guide - Object-Relational Features, PL/SQL Users Guide and Reference, and Oracle9i Java Developers Guide.
Organization
This document contains:
Part I: Introduction
This part introduces several different ways that you can write Oracle applications. You might need to use more than one language or development environment for a single application. Some database features are only supported, or are easier to access from, certain languages. Chapter 1, "Understanding the Oracle Programmatic Environments" outlines the strengths of the languages, development environments, and APIs that Oracle provides.
xxi
and scalability, and reduces the amount of application logic you code by making the database responsible for things like error checking and fast data access. Chapter 2, "Managing Schema Objects" explains how to manage objects such as tables, views, numeric sequences, and synonyms. It also discusses performance enhancements to data retrieval through the use of indexes and clusters. Chapter 3, "Selecting a Datatype" explains how to represent your business data in the database. The datatypes include xed- and variable-length character strings, numeric data, dates, raw binary data, and row identiers (ROWIDs). Chapter 4, "Maintaining Data Integrity Through Constraints" explains how to use constraints to move error-checking logic out of your application and into the database. Chapter 5, "Selecting an Index Strategy" and Chapter 6, "Speeding Up Index Access with Index-Organized Tables" explain how to speed up queries. Chapter 7, "How Oracle Processes SQL Statements" explains SQL topics such as commits, cursors, and locking that you can take advantage of in your applications. Chapter 8, "Coding Dynamic SQL Statements" describes dynamic SQL, compares native dynamic SQL to the DBMS_SQL package, and explains when to use dynamic SQL. Chapter 9, "Using Procedures and Packages" explains how to store reusable procedures in the database, and how to group procedures into packages. Chapter 10, "Calling External Procedures" explains how to code the bodies of computationally intensive procedures in languages other than PL/SQL.
xxii
Related Documentation
For more information, see these Oracle resources: Use the PL/SQL Users Guide and Reference to learn PL/SQL and to get a complete description of this high-level programming language, which is Oracle Corporations procedural extension to SQL. The Oracle Call Interface (OCI) is described in Oracle Call Interface Programmers Guide and Oracle C++ Call Interface Programmers Guide . You can use the OCI to build third-generation language (3GL) applications that access the Oracle Server. Oracle Corporation also provides the Pro* series of precompilers, which allow you to embed SQL and PL/SQL in your application programs. If you write 3GL application programs in C, C++, COBOL, or FORTRAN that incorporate embedded
xxiii
SQL, then refer to the corresponding precompiler manual. For example, if you program in C or C++, then refer to the Pro*C/C++ Precompiler Programmers Guide. Oracle Developer/2000 is a cooperative development environment that provides several tools including a form builder, reporting tools, and a debugging environment for PL/SQL. If you use Developer/2000, then refer to the appropriate Oracle Tools documentation. For SQL information, see the Oracle9i SQL Reference and Oracle9i Database Administrators Guide. For basic Oracle concepts, see Oracle9i Database Concepts. For developing applications that manipulate XML data, see Oracle9i XML Developers Kits Guide - XDK and Oracle9i XML API Reference - XDK and Oracle XML DB. Many of the examples in this book use the sample schemas of the seed database, which is installed by default when you install Oracle. Refer to Oracle9i Sample Schemas for information on how these schemas were created and how you can use them yourself. In North America, printed documentation is available for sale in the Oracle Store at
http://oraclestore.oracle.com/
Customers in Europe, the Middle East, and Africa (EMEA) can purchase documentation from
http://www.oraclebookshop.com/
Other customers can contact their Oracle representative to purchase printed documentation. To download free release notes, installation documentation, white papers, or other collateral, please visit the Oracle Technology Network (OTN). You must register online before using OTN; registration is free and can be done at
http://otn.oracle.com/admin/account/membership.html
If you already have a username and password for OTN, then you can go directly to the documentation section of the OTN Web site at
http://otn.oracle.com/docs/index.htm
xxiv
This search engine has a number of features that you might nd useful, such as searching for examples, looking up SQL and PL/SQL syntax, and formatting large numbers of search results into a "virtual book".
Conventions
This section describes the conventions used in the text and code examples of this documentation set. It describes:
s
Conventions in Text
We use various conventions in text to help you more quickly identify special terms. The following table describes those conventions and provides examples of their use.
Convention Bold Meaning Example
Bold typeface indicates terms that are When you specify this clause, you create an dened in the text or terms that appear in index-organized table. a glossary, or both. Italic typeface indicates book titles or emphasis. Oracle9i Database Concepts Ensure that the recovery catalog and target database do not reside on the same disk. You can specify this clause only for a NUMBER column. You can back up the database by using the BACKUP command. Query the TABLE_NAME column in the USER_ TABLES data dictionary view. Use the DBMS_STATS.GENERATE_STATS procedure.
Italics
Uppercase monospace typeface indicates elements supplied by the system. Such elements include parameters, privileges, datatypes, RMAN keywords, SQL keywords, SQL*Plus or utility commands, packages and methods, as well as system-supplied column names, database objects and structures, usernames, and roles.
xxv
Meaning Lowercase monospace typeface indicates executables, lenames, directory names, and sample user-supplied elements. Such elements include computer and database names, net service names, and connect identiers, as well as user-supplied database objects and structures, column names, packages and classes, usernames and roles, program units, and parameter values.
Example Enter sqlplus to open SQL*Plus. The password is specied in the orapwd le. Back up the datales and control les in the /disk1/oracle/dbs directory. The department_id, department_name, and location_id columns are in the hr.departments table.
Set the QUERY_REWRITE_ENABLED initialization parameter to true. Note: Some programmatic elements use a mixture of UPPERCASE and lowercase. Connect as oe user. Enter these elements as shown. The JRepUtil class implements these methods.
You can specify the parallel_clause. Run Uold_release.SQL where old_ release refers to the release you installed prior to upgrading.
The following table describes typographic conventions used in code examples and provides examples of their use.
Convention [] Meaning Brackets enclose one or more optional items. Do not enter the brackets. Braces enclose two or more items, one of which is required. Do not enter the braces. Example DECIMAL (digits [ , precision ]) {ENABLE | DISABLE}
{}
A vertical bar represents a choice of two {ENABLE | DISABLE} or more options within brackets or braces. [COMPRESS | NOCOMPRESS] Enter one of the options. Do not enter the vertical bar.
xxvi
Convention ...
Example
That we have omitted parts of the code that are not directly related to the example That you can repeat a portion of the code
. . . Other notation
Vertical ellipsis points indicate that we have omitted several lines of code not directly related to the example. You must enter symbols other than brackets, braces, vertical bars, and ellipsis points as shown. Italicized text indicates placeholders or variables for which you must supply particular values. Uppercase typeface indicates elements supplied by the system. We show these terms in uppercase in order to distinguish them from terms you dene. Unless terms appear in brackets, enter them in the order and with the spelling shown. However, because these terms are not case sensitive, you can enter them in lowercase. Lowercase typeface indicates programmatic elements that you supply. For example, lowercase indicates names of tables, columns, or les. Note: Some programmatic elements use a mixture of UPPERCASE and lowercase. Enter these elements as shown. acctbal NUMBER(11,2); acct CONSTANT NUMBER(4) := 3;
Italics
CONNECT SYSTEM/system_password DB_NAME = database_name SELECT last_name, employee_id FROM employees; SELECT * FROM USER_TABLES; DROP TABLE hr.employees;
UPPERCASE
lowercase
SELECT last_name, employee_id FROM employees; sqlplus hr/hr CREATE USER mjones IDENTIFIED BY ty3MU9;
Documentation Accessibility
Our goal is to make Oracle products, services, and supporting documentation accessible, with good usability, to the disabled community. To that end, our documentation includes features that make information available to users of assistive technology. This documentation is available in HTML format, and contains markup to facilitate access by the disabled community. Standards will continue to evolve over time, and Oracle Corporation is actively engaged with other
xxvii
market-leading technology vendors to address technical obstacles so that our documentation can be accessible to all of our customers. For additional information, visit the Oracle Accessibility Program Web site at
http://www.oracle.com/accessibility/
JAWS, a Windows screen reader, may not always correctly read the code examples in this document. The conventions for writing code require that closing braces should appear on an otherwise empty line; however, JAWS may not always read a line of text that consists solely of a bracket or brace.
Accessibility of Code Examples in Documentation Accessibility of Links to External Web Sites in Documentation This documentation may contain links to Web sites of other companies or organizations that Oracle Corporation does not own or control. Oracle Corporation neither evaluates nor makes any representations regarding the accessibility of these Web sites.
xxviii
xxix
Enhancements to ashback query You can perform ashback queries using the AS OF clause of the SELECT statement rather than going through the DBMS_FLASHBACK package. This technique is very exible, allowing you to perform joins, set operations, subqueries, and views using different date/time or SCN settings for each table in the query. You can also restore or capture past data by using ashback queries inside INSERT or CREATE TABLE AS SELECT statements.
See Also: "Querying Data at a Point in Time (Flashback Query)"
on page 7-43
s
Using PL/SQL Records in INSERT and UPDATE Statements When you represent related data items using a PL/SQL record, you can perform insert and update operations using the entire record, instead of specifying each record eld separately.
See Also: "Using PL/SQL Records in SQL INSERT and UPDATE
Changes to Java Programming Practices To develop using EJBs or CORBA, you should use the J2EE components that are part of Oracle9i Application Server. EJBs and CORBA are no longer supported within the database. You can still access the database from these components, just from a middle-tier application server. You can still write Java stored procedures and Java methods for object types within the database.
See Also: "Overview of Java Stored Procedures, JDBC, and SQLJ"
on page 1-8
s
Ability to rename constraints If a data management application experiences problems because it tries to create a constraint when the constraint already exists, you can rename the existing constraint to avoid the conict. If you track down a constraint with a cryptic system-generated name, you can give it a descriptive name to make it easier to enable and disable later.
xxx
Enhanced support for NCHAR, NVARCHAR2, and NCLOB types These globalization-support types can now be used as attributes of SQL and PL/SQL object types, and in PL/SQL collection types such as varrays and nested tables.
New XML programming capabilities New and enhanced built-in types, such as XMLType and XDBURIType, let you delegate XML parsing, storage, and retrieval to the database. Details are in the XML documentation rather than this book.
Enhanced UTL_FILE package The UTL_FILE package has a number of new functions for performing popular le operations. You can seek, auto-ush, read and write binary data, delete les, change le permissions, and more. You should begin using the CREATE DIRECTORY statement (using double quotation marks around any lowercase names), rather than the UTL_FILE_DIR initialization parameter.
See Also: Oracle9i Supplied PL/SQL Packages and Types Reference
User-dened constructors You can now override the system default constructor for an object type with your own function.
See Also:
s
Access to LOB data within triggers You can access or change LOB data within BEFORE and INSTEAD OF triggers, using the :NEW variable.
See Also: "Example: Modifying LOB Columns with a Trigger" on
page 15-17
s
Synonyms for types You can now dene synonyms for types.
See Also: "Managing Synonyms" on page 2-28
xxxi
Scrollable cursors in Pro*C/C++ applications Scrollable cursors let you move forward and backward through the result set in a Pro*C/C++ application.
See Also: "Highlights of Pro*C/C++ Features" on page 1-23
Support for Connection Pooling in Pro*C/C++ The Connection Pool feature in Pro*C/C++ helps you optimise the performance of Pro*C/C++ applications.
See Also: "Highlights of Pro*C/C++ Features" on page 1-23
Better linking in online documentation Many of the cross-references from this book to other books have been made more specic, so that they link to a particular place within another book rather than to the table of contents. Because this is an ongoing project, not all links are improved in this edition. If you are reading a printed copy of this book, you can nd the online equivalent at http://tahiti.oracle.com/, with full search capability.
Release 1 (9.0.1)
s
Integration of SQL and PL/SQL parsers PL/SQL now supports the complete range of syntax for SQL statements, such as INSERT, UPDATE, DELETE, and so on. If you received errors for valid SQL syntax in PL/SQL programs before, those statements should now work.
See Also: Because of more consistent error-checking, you might
nd that some invalid code is now found at compile time instead of producing an error at runtime, or vice versa. You might need to change the source code as part of the migration procedure. See Oracle9i Database Migration for details on the complete migration procedure.
s
Resumable Storage Allocation When an application encounters some kinds of storage allocation errors, it can suspend operations and take action such as resolving the problem or notifying an operator. The operation can be resumed when storage is added or freed.
xxxii
on page 7-40
s
Flashback Query Table data can be queried as it existed at a point in time. This lets applications query, compare, or recover past data without involving the DBA and without an expensive recovery operation. The current table data remains available to other applications throughout.
See Also: "Querying Data at a Point in Time (Flashback Query)"
on page 7-43
s
WITH Clause for Reusing Complex Subqueries Rather than repeat a complex subquery, you can give it a name and refer to that name multiple times within the same query. This is convenient for coding, and helps the optimizer nd common code that can be optimized.
See Also: "Tip: Referencing the Same Subquery Multiple Times"
on page 2-7
s
New Date and Time Types The new datatype TIMESTAMP records time values including fractional seconds. New datatypes TIMESTAMP WITH TIME ZONE and TIMESTAMP WITH LOCAL TIME ZONE allow you to adjust date and time values to account for time zone differences. You can specify whether the time zone observes daylight savings time, to account for anomalies when clocks shift forward or backward. New datatypes INTERVAL DAY TO SECOND and INTERVAL YEAR TO MONTH represent differences between two date and time values, simplifying date arithmetic.
See Also:
s s
"Summary of Oracle Built-In Datatypes" on page 3-2 "Representing Date and Time Data" on page 3-14
Better Integration of LOB Datatypes You can operate on LOB types much like other similar types. You can use character functions on CLOB and NCLOB types. You can treat BLOB types as
xxxiii
RAWs. Conversions between LOBs and other types are much simpler, particularly when converting from LONG to LOB types.
See Also:
s s s
"Representing Large Data Types" on page 3-27 "How Oracle Converts Datatypes" on page 3-38 "Representing Character Data" on page 3-10
Improved Globalization and National Language Support Data can be stored in Unicode format using xed-width or variable-width character sets. String handling and storage declarations can be specied using byte lengths, or character lengths where the number of bytes is computed for you. You can set up the entire database to use the same length semantics for strings, or specify the settings for individual procedures; this setting is remembered if a procedure is invalidated.
See Also: "Representing Character Data" on page 3-10
Enhancements to Bulk Operations You can now perform bulk SQL operations, such as bulk fetches, using native dynamic SQL (the EXECUTE IMMEDIATE statement). You can perform bulk insert or update operations that continue despite errors on some rows, then examine the problems after the operation is complete.
See Also: "Overview of Bulk Binds" on page 9-18
Improved Support for PL/SQL Web Applications The UTL_HTTP and UTL_SMTP packages have a number of enhancements, such as letting you access password-protected web pages, sending e-mail with attachments, and so on.
See Also: Chapter 18, "Developing Web Applications with
Native Compilation of PL/SQL Code Improve performance by compiling Oracle-supplied and user-written stored procedures into native executables, using typical C development tools. This
xxxiv
setting is saved so that the procedure is compiled the same way if it is later invalidated.
See Also: "Compiling PL/SQL Procedures for Native Execution"
on page 9-22
s
Oracle C++ Call Interface (OCCI) API The OCCI API lets you write fast, low-level database applications using C++. It is similar to the existing Oracle Call Interface (OCI) API.
See Also: "Overview of OCI and OCCI" on page 1-26
Secure Application Roles In Oracle9i, application developers no longer need to secure a role by embedding passwords inside applications. They can create application roles and specify which PL/SQL package is authorized to enable the roles. These application roles, those enabled by PL/SQL packages, are called secure application roles.
See Also: Creating Secure Application Roles on page 11-14
Creating Application Contexts You can create an application context by entering a command like:
CREATE CONTEXT Order_entry USING Apps.Oe_ctx;
Alternatively, you can use Oracle Policy Manager to create an application context.
See Also: Step 2. Create an Application Context on page 12-18
s
Dedicated External Procedure Agents You can run external procedure agents (the EXTPROC entry in tnsnames.ora) under different instances of Oracle or on entirely separate machines. This lets you congure external procedures more robustly, so that if one external procedure crashes, other external procedures can continue running in a different agent process.
xxxv
See Also:
s s
"Loading External C Procedures" on page 10-6 "Publishing External Procedures" on page 10-8
xxxvi
Part I
Introduction To Oracle9i Application Development
This part contains the following chapter:
s
1
Understanding the Oracle Programmatic Environments
This chapter presents brief introductions to these application development systems:
s
Overview of PL/SQL Overview of Java Stored Procedures, JDBC, and SQLJ Overview of Pro*C/C++ Overview of Pro*COBOL Overview of OCI and OCCI Overview of Oracle Objects for OLE (OO4O) Choosing a Programming Environment
Client/Server Model
In a traditional client/server program, the code of your application runs on a machine other than the database server. Database calls are transmitted from this client machine to the database server. Data is transmitted from the client to the server for insert and update operations, and returned from the server to the client for query operations. The data is processed on the client machine. Client/server programs are typically written using precompilers, where SQL statements are embedded within the code of another language such as C, C++, or COBOL.
Server-Side Coding
You can develop application logic that resides entirely inside the database, using triggers that are executed automatically when changes occur in the database, or stored procedures that are called explicitly. Ofoading the work from your application lets you reuse code that performs verication and cleanup, and control database operations from a variety of clients. For example, by making stored procedures callable through a web server, you can construct a web-based user interface that performs the same functions as a client/server application.
User Interface
The interface that your application displays to end users depends on the technology behind the application, as well as the needs of the users themselves. Experienced users might enter SQL commands that are passed on to the database. Novice users might be shown a graphical user interface that uses the graphics libraries of the client system (such as Windows or X-Windows). Any of these traditional user interfaces can also be provided in a web using HTML and Java.
1-2
Overview of PL/SQL
Overview of PL/SQL
PL/SQL is Oracles procedural extension to SQL, the standard database access language. An advanced 4GL (fourth-generation programming language), PL/SQL offers seamless SQL access, tight integration with the Oracle server and tools, portability, security, and modern software engineering features such as data encapsulation, overloading, exception handling, and information hiding. With PL/SQL, you can manipulate data with SQL statements, and control program ow with procedural constructs such as IF-THEN and LOOP. You can also declare constants and variables, dene procedures and functions, use collections and object types, and trap run-time errors. Applications written using any of the Oracle programmatic interfaces can call PL/SQL stored procedures and send blocks of PL/SQL code to the server for execution. 3GL applications can access PL/SQL scalar and composite datatypes through host variables and implicit datatype conversion. Because it runs inside the database, PL/SQL code is very efcient for data-intensive operations, and minimizes network trafc in client/server applications. PL/SQLs tight integration with Oracle Developer lets you develop the client and server components of your application in the same language, then partition the
Overview of PL/SQL
components for optimal performance and scalability. Also, Oracles Web Forms lets you deploy your applications in a multitier Internet or intranet environment without modifying a single line of code. For more information, see PL/SQL Users Guide and Reference.
Advantages of PL/SQL
PL/SQL is a completely portable, high-performance transaction processing language that offers the following advantages:
1-4
Overview of PL/SQL
datatypes, reducing conversions as data is passed between applications and the database. Dynamic SQL is a programming technique that lets you build and process SQL statements "on the y" at run time. It gives PL/SQL exibility comparable to scripting languages such as Perl, Korn shell, and Tcl.
Better Performance
If your application is database intensive, you can use PL/SQL blocks to group SQL statements before sending them to Oracle for execution. This can drastically reduce the communication overhead between your application and Oracle. PL/SQL stored procedures are compiled once and stored in executable form, so procedure calls are quick and efcient. A single call can start a compute-intensive stored procedure, reducing network trafc and improving round-trip response times. Executable code is automatically cached and shared among users, lowering memory requirements and invocation overhead.
Higher Productivity
PL/SQL adds procedural capabilities to such as Oracle Forms and Oracle Reports. For example, you can use an entire PL/SQL block in an Oracle Forms trigger instead of multiple trigger steps, macros, or user exits. PL/SQL is the same in all environments. As soon as you master PL/SQL with one Oracle tool, you can transfer your knowledge to other tools, and so multiply the productivity gains. For example, scripts written with one tool can be used by other tools.
Scalability
PL/SQL stored procedures increase scalability by centralizing application processing on the server. Automatic dependency tracking helps to develop scalable applications.
Overview of PL/SQL
The shared memory facilities of the shared server (formerly known as Multi-Threaded Server or MTS) enable Oracle to support many thousands of concurrent users on a single node. For more scalability, you can use the Oracle Net Connection Manager to multiplex network connections.
Maintainability
Once validated, a PL/SQL stored procedure can be used with condence in any number of applications. If its denition changes, only the procedure is affected, not the applications that call it. This simplies maintenance and enhancement. Also, maintaining a procedure on the server is easier than maintaining copies on various client machines.
1-6
Overview of PL/SQL
Portability
Applications written in PL/SQL can run on any operating system and hardware platform where Oracle runs. You can write portable program libraries and reuse them in different environments.
Security
PL/SQL stored procedures let you divide application logic between the client and the server, to prevent client applications from manipulating sensitive Oracle data. Database triggers written in PL/SQL can prevent applications from making certain updates, and can audit user queries. You can restrict access to Oracle data by allowing users to manipulate it only through stored procedures that have a restricted set of privileges. For example, you can grant users access to a procedure that updates a table, but not grant them access to the table itself.
DBMS_PIPE is used to communicate between sessions. DBMS_ALERT is used to broadcast alerts to users. DBMS_LOCK and DBMS_TRANSACTION are used for lock and transaction management. DBMS_AQ is used for Advanced Queuing. DBMS_LOB is for your manipulation of large objects. DBMS_ROWID is used for employing ROWIDs. UTL_RAW is for the RAW facility. UTL_REF is for work with REFs.
DBMS_SESSION is for session management by DBAs. DBMS_SYSTEM is used to set events for debugging. DBMS_SPACE and DBMS_SHARED_POOL obtain space information and reserve shared pool resources. DBMS_JOB is used to schedule jobs in the server.
SQL CALL statements. Embedded SQL CALL statements. PL/SQL blocks, subprograms and packages. DML statements (INSERT, UPDATE, DELETE, and SELECT). Oracle development tools such as OCI, Pro*C/C++ and Oracle Developer. Oracle Java interfaces such as JDBC, SQLJ statements, CORBA, and Enterprise Java Beans. Method calls from object types.
1-8
table. Triggers enforce business rules, prevent incorrect values from being stored, and reduce the need to perform checking and cleanup operations in each application.
Stored procedures and triggers are compiled once, are easy to use and maintain, and require less memory and computing overhead. Network bottlenecks are avoided, and response time is improved. Distributed applications are easier to build and use. Computation-bound procedures run faster in the server. Data access can be controlled by letting users only have stored procedures and triggers that execute with their deners privileges instead of invokers rights. PL/SQL and Java stored procedures can call each other. Java in the server follows the Java language specication and can use the SQLJ standard, so that non-Oracle databases are also supported. Stored procedures and triggers can be reused in different applications as well as different geographic sites.
Type 1. A JDBC-ODBC bridge. Software must be installed on client systems. Type 2. Has Native methods (calls C or C++) and Java methods. Software must be installed on the client. Type 3. Pure Java. The client uses sockets to call middleware on the server. Type 4. The most pure Java solution. Talks directly to the database using Java sockets.
JDBC is based on the X/Open SQL Call Level Interface, and complies with the SQL92 Entry Level standard.
You can use JDBC to do dynamic SQL. Dynamic SQL means that the embedded SQL statement to be executed is not known before the application is run, and requires input to build the statement. The drivers that are implemented by Oracle have extensions to the capabilities in the JDBC standard that was dened by Sun Microsystems. Oracles implementations of JDBC drivers are described next. The Oracle database server support of and extensions to various levels of the JDBC standard are described in "How Oracle Supports and Extends the JDBC Standards" on page 1-11.
1-10
Application Server. Oracle9iAS provides middleware services and tools that support access between applications and browsers.
Support for Oracle datatypes Performance enhancement by row prefetching Performance enhancement by execution batching Specication of query column types to save round-trips Control of DatabaseMetaData calls
Oracle supports all APIs from the JDBC 2.0 standard, including the core APIs, optional packages, and numerous extensions. Some of the highlights include datasources, JTA and distributed transactions. Oracle has supports these features from the JDBC 3.0 standard:
s
Support for JDK 1.4. Toggling between local and global transactions. Transaction savepoints. Re-use of prepared statements by connection pools.
1-11
class JdbcTest { public static void main (String args []) throws SQLException { // Load Oracle driver DriverManager.registerDriver (new oracle.jdbc.OracleDriver()); // Connect to the local database Connection conn = DriverManager.getConnection ("jdbc:oracle:thin:@myhost:1521:orcl", "scott", "tiger"); // Query the employee names Statement stmt = conn.createStatement (); ResultSet rset = stmt.executeQuery ("SELECT ENAME FROM EMP");
1-12
// Print the name out while (rset.next ()) System.out.println (rset.getString (1)); // Close the result set, statement, and the connection rset.close(); stmt.close(); conn.close(); } }
An Oracle extension to the JDBC drivers is a form of the getConnection() method that uses a Properties object. The Properties object lets you specify user, password, and database information as well as row prefetching and execution batching. To use the OCI driver in this code, replace the Connection statement with:
Connection conn = DriverManager.getConnection ("jdbc:oracle:oci8:@MyHostString", "scott", "tiger");
where MyHostString is an entry in the TNSNAMES.ORA le. If you are creating an applet, the getConnection() and registerDriver() strings will be different.
1-13
A language specication for embedding static SQL statements in Java source code which has been agreed to by a consortium of database companies, including Oracle, and by Sun, author of Java. The specication has been accepted by ANSI as a software standard. A software tool developed by Oracle to the standard, with extensions to the standard to support Oracle features. That tool is the subject of this brief overview.
SQLJ Tool
The Oracle software tool SQLJ has two parts: a translator and a runtime. You execute on any Java VM with a JDBC driver and a SQLJ runtime library. A SQLJ source le contains Java source with embedded static SQL statements. The SQLJ translator is 100% Pure Java and is portable to any standard JDK 1.1 or higher VM. The Oracle SQLJ implementation typically runs in three steps:
s
Translates SQLJ source to Java code with calls to the SQLJ runtime. The SQLJ translator converts the source code to pure Java source code, and can check the syntax and semantics of static SQL statements against a database schema and verify the type compatibility of host variables with SQL types. Compiles using the Java compiler. Customizes for the target database. SQLJ optionally generates "prole" les with Oracle-specic customizing.
Oracle9i supports SQLJ stored procedures, functions, and triggers which execute in a Java VM integrated with the data server. SQLJ is integrated with Oracles JDeveloper. Source-level debugging support is available in JDeveloper. Here is an example of the simplest SQLJ executable statement, which returns one value because empno is unique in the emp table:
String name; #sql { SELECT ename INTO :name FROM emp WHERE empno=67890 }; System.out.println("Name is " + name + ", employee number = " + empno);
Each host variable (or qualied name or complex Java host expression) is preceded by a colon (:). Other SQLJ statements are declarative (declares Java types) and allow
1-14
you to declare an iterator (a construct related to a database cursor) for queries that retrieve many values:
#sql iterator EmpIter (String EmpNam, int EmpNumb);
Benets of SQLJ
SQLJs simple extensions to Java allow rapid development and easy maintenance of applications that perform database operations through embedded SQL. In particular, Oracles implementation of SQLJ:
s
Provides a concise, legible mechanism for database access from static SQL. Most SQL in applications is static. SQLJ provides more concise and less error-prone static SQL constructs than JDBC does. Checks static SQL at translate time. Provides exible deployment congurations. This makes it possible to implement SQLJ on the client or database side or in the middle tier. Supports a software standard. SQLJ is an effort of a group of vendors and will be supported by all of them. Applications can access multiple database vendors. Provides source code portability. Executables can be used with all of the vendors DBMSs presuming the code does not rely on any vendor-specic features. Enforces a uniform programming style for the clients and the servers. Integrates the SQLJ translator with JDeveloper, a graphical IDE that provides SQLJ translation, Java compilation, prole customizing, and debugging at the source code level, all in one step. Provides an SQL Checker module for verication of syntax and semantics at translate-time. Includes Oracle type extensions. Datatypes supported are LOBs, ROWIDs, REF CURSORs, VARRAYs, nested tables, user-dened object types, as well as other datatypes such as RAW and NUMBER.
1-15
JDBC provides ne-grained control of the execution of dynamic SQL from Java, while SQLJ provides a higher-level binding to SQL operations in a specic database schema. Here are some differences:
s
SQLJ source code is more concise than equivalent JDBC source code. SQLJ uses database connections to type-check static SQL code. JDBC, being a completely dynamic API, does not. SQLJ programs allow direct embedding of Java bind expressions within SQL statements. JDBC requires a separate get or set call statement for each bind variable and species the binding by position number. SQLJ provides strong typing of query outputs and return parameters and allows type-checking on calls. JDBC passes values to and from SQL without compile-time type checking. SQLJ provides simplied rules for calling SQL stored procedures and functions. The JDBC specication requires a generic call to a stored procedure (or function), fun, to have the following syntax (we show SQL92 and Oracle escape syntaxes, which are both allowed):
prepStmt.prepareCall("{call fun(?,?)}"); //stored procedure SQL92 prepStmt.prepareCall("{? = call fun(?,?)}"); //stored function SQL92 prepStmt.prepareCall("begin fun(:1,:2);end;"); //stored procedure Oracle prepStmt.prepareCall("begin :1 := fun(:2,:3);end;");//stored func Oracle
SQLJ source les can contain JDBC calls. SQLJ and JDBC are interoperable. Oracles JPublisher tool generates custom Java classes to be used in your SQLJ or JDBC application for mappings to Oracle object types and collections. Java and PL/SQL stored procedures can be used interchangeably.
1-16
Two object types, PERSON and ADDRESS A typed table for PERSON objects An EMPLOYEE table that includes an ADDRESS column and two columns of PERSON references
SET ECHO ON; / /*** Clean up in preparation ***/ DROP TABLE EMPLOYEES / DROP TABLE PERSONS / DROP TYPE PERSON FORCE / DROP TYPE ADDRESS FORCE / /*** Create address UDT ***/ CREATE TYPE address AS OBJECT ( street VARCHAR(60), city VARCHAR(30), state CHAR(2), zip_code CHAR(5) ) / /*** Create person UDT containing an embedded address UDT ***/ CREATE TYPE person AS OBJECT ( name VARCHAR(30), ssn NUMBER, addr address ) / /*** Create a typed table for person objects ***/ CREATE TABLE persons OF person / /*** Create a relational table with two columns that are REFs to person objects, as well as a column which is an Address ADT. ***/
1-17
CREATE TABLE employees ( empnumber INTEGER PRIMARY KEY, person_data REF person, manager REF person, office_addr address, salary NUMBER ) /*** Insert some data--2 objects into the persons typed table ***/ INSERT INTO persons VALUES ( person('Wolfgang Amadeus Mozart', 123456, address('Am Berg 100', 'Salzburg', 'AT','10424'))) / INSERT INTO persons VALUES ( person('Ludwig van Beethoven', 234567, address('Rheinallee', 'Bonn', 'DE', '69234'))) / /** Put a row in the employees table **/ INSERT INTO employees (empnumber, office_addr, salary) VALUES ( 1001, address('500 Oracle Parkway', 'Redwood Shores', 'CA', '94065'), 50000) / /** Set the manager and person REFs for the employee **/ UPDATE employees SET manager = (SELECT REF(p) FROM persons p WHERE p.name = 'Wolfgang Amadeus Mozart') / UPDATE employees SET person_data = (SELECT REF(p) FROM persons p WHERE p.name = 'Ludwig van Beethoven') / COMMIT / QUIT
Next, JPublisher is used to generate the Address class for mapping to Oracle ADDRESS objects. We omit the details. The following SQLJ sample declares and sets an input host variable of Java type Address to update an ADDRESS object in a column of the employees table. Both before and after the update, the ofce address is selected into an output host variable of type Address and printed for verication.
...
1-18
// Updating an object static void updateObject() { Address addr; Address new_addr; int empno = 1001; try { #sql { SELECT office_addr INTO :addr FROM employees WHERE empnumber = :empno }; System.out.println("Current office address of employee 1001:"); printAddressDetails(addr); /* Now update the street of address */ String street ="100 Oracle Parkway"; addr.setStreet(street); /* Put updated object back into the database */ try { #sql { UPDATE employees SET office_addr = :addr WHERE empnumber = :empno }; System.out.println ("Updated employee 1001 to new address at Oracle Parkway."); /* Select new address to verify update */ try { #sql { SELECT office_addr INTO :new_addr FROM employees WHERE empnumber = :empno }; System.out.println("New office address of employee 1001:"); printAddressDetails(new_addr);
1-19
Programming with J2EE, OC4J, SOAP, JAAS, Servlets, JSPs, EJBs, CORBA, and UDDI
} catch (SQLException exn) { System.out.println("Verification SELECT failed with "+exn); } } catch (SQLException exn) { System.out.println("UPDATE failed with "+exn); } } catch (SQLException exn) { System.out.println("SELECT failed with "+exn); } } ...
Note the use of the setStreet() accessor method of the Address instance. Remember that JPublisher provides such accessor methods for all attributes in any custom Java class that it produces.
Programming with J2EE, OC4J, SOAP, JAAS, Servlets, JSPs, EJBs, CORBA, and UDDI
To develop applications with all these industry-standard components, you use the Java support in the Oracle9i Application Server. You can nd Oracle9iAS documentation at http://tahiti.oracle.com/. With the introduction of Oracle9i Application Server Containers for J2EE (OC4J)--a new, lighter-weight, easier-to-use, faster, and certied J2EE container--Oracle will desupport the Java 2 Enterprise Edition (J2EE) and CORBA stacks from the database, starting with Oracle9i Database release 2. However, the database-embedded Java VM (Oracle JVM) will still be present and will continue to be enhanced to offer Java 2 Standard Edition (J2SE) features, Java Stored Procedures, JDBC, and SQLJ in the database. As of Oracle9i Database release 2 (version 9.2.0), Oracle will no longer support
1-20
Overview of Pro*C/C++
Enterprise Java Beans (EJB) Container Oracle JavaServer Pages engine (OJSP) Oracle Servlet Engine (OSE)
The embedded Common Object Request Broker Architecture (CORBA) framework, based on Visibroker for Java.
Customers will no longer be able to deploy servlets, JSP pages, EJBs, and CORBA objects in Oracle databases. Oracle9i Database release 1 (version 9.0.1) will be the last database release to support the J2EE and CORBA stack. Oracle is encouraging customers to migrate existing J2EE applications running in the database to OC4J now.
Overview of Pro*C/C++
The Pro*C/C++ precompiler is a software tool that allows the programmer to embed SQL statements in a C or C++ source le. Pro*C/C++ reads the source le as input and outputs a C or C++ source le that replaces the embedded SQL statements with Oracle runtime library calls, and is then compiled by the C or C++ compiler. When there are errors found during the precompilation or the subsequent compilation, modify your precompiler input le and re-run the two steps.
1-21
Overview of Pro*C/C++
/* Define an indicator structure to correspond to the host output structure. */ struct { short emp_name_ind; short sal_ind; short comm_ind; } emprec_ind; ... /* Select columns ename, sal, and comm given the users input for empno. */ EXEC SQL SELECT ename, sal, comm INTO :emprec INDICATOR :emprec_ind FROM emp WHERE empno = :emp_number; ...
The embedded SELECT statement is only slightly different from an interactive (SQL*Plus) version. Every embedded SQL statement begins with EXEC SQL. The colon, :, precedes every host (C) variable. The returned values of data and indicators (set when the data value is NULL or character columns have been truncated) can be stored in structs (such as in the above code fragment), in arrays, or in arrays of structs. Multiple result set values are handled very simply in a manner that resembles the case shown, where there is only one result, because of the unique employee number. You use the actual names of columns and tables in embedded SQL. Use the default precompiler option values, or you can enter values which give you control over the use of resources, how errors are reported, the formatting of output, and how cursors (which correspond to a particular connection or SQL statement) are managed. Cursors are used when there are multiple result set values. Enter the options either in a conguration le, on the command line, or inline inside your source code with a special statement that begins with EXEC ORACLE. If there are no errors found, you can then compile, link, and execute the output source le, like any other C program that you write. Use the precompiler to create server database access from clients that can be on many different platforms. Pro*C/C++ allows you the freedom to design your own user interfaces and to add database access to existing applications. Before writing your embedded SQL statements, you may want to test interactive versions of the SQL in SQL*Plus. You then make only minor changes to start testing your embedded SQL application.
1-22
Overview of Pro*C/C++
You can write your application in either C or C++. You can write multi-threaded programs if your platform supports a threads package. Concurrent connections are supported in either single-threaded or multi-threaded applications. You can improve performance by embedding PL/SQL blocks. These blocks can call functions or procedures written by you or provided in Oracle packages, in either Java or PL/SQL. Using precompiler options, you can check the syntax and semantics of your SQL or PL/SQL statements during precompilation, as well as at runtime. You can call stored PL/SQL and Java subprograms. Modules written in COBOL or in C can be called from Pro*C/C++. External C procedures in shared libraries are callable by your program. You can conditionally precompile sections of your code so that they can execute in different environments. You can use arrays, or structures, or arrays of structures as host and indicator variables in your code to improve performance. You can deal with errors and warnings so that data integrity is guaranteed. As a programmer, you control how errors are handled. Your program can convert between internal datatypes and C language datatypes. The Oracle Call Interface (OCI) and Oracle C++ Interface (OCCI), lower-level C and C++ interfaces, are available for use in your precompiler source. Pro*C/C++ supports dynamic SQL, a technique that allows users to input variable values and statement syntax. Pro*C/C++ can use special SQL statements to manipulate tables containing user-dened object types. An Object Type Translator (OTT) will map the object types and named collection types in your database to structures and headers that you will then include in your source. Two kinds of collection types, nested tables and VARRAYs, are supported with a set of SQL statements that allow a high degree of control over data.
1-23
Overview of Pro*COBOL
Large Objects (LOBs, CLOBs, NCLOBs, and external les known as BFILEs) are accessed by another set of SQL statements. A new ANSI SQL standard for dynamic SQL is supported for new applications, so that you can execute SQL statements with a varying number of host variables. An older technique for dynamic SQL is still usable by pre-existing applications. Globalization support lets you use multibyte characters and UCS2 Unicode data. Using scrollable cursors, you can move backward and forward through a result set. For example, you can fetch the last row of the result set, or jump forward or backward to an absolute or relative position within the result set. A connection pool is a group of physical connections to a database that can be shared by several named connections. Enabling the connection pool option can help to optimise the performance of Pro*C/C++ application. The connection pool option is not enabled by default.
Overview of Pro*COBOL
The Pro*COBOL precompiler is a software tool that allows the programmer to embed SQL statements in a COBOL source code le. Pro*COBOL reads the source le as input and outputs a COBOL source le that replaces the embedded SQL statements with Oracle runtime library calls, and is then compiled by the COBOL compiler. When there are errors found during the precompilation or the subsequent compilation, modify your precompiler input le and re-run the two steps.
1-24
Overview of Pro*COBOL
05 SALARY PIC S9(5)V99 COMP-3 VALUE ZERO. 05 COMMISSION PIC S9(5)V99 COMP-3 VALUE ZERO. 05 COMM-IND PIC S9(4) COMP VALUE ZERO. ... PROCEDURE DIVISION. ... EXEC SQL SELECT ENAME, SAL, COMM INTO :EMP-NAME, :SALARY, :COMMISSION:COMM-IND FROM EMP WHERE EMPNO = :EMP_NUMBE END-EXEC. ...
The embedded SELECT statement is only slightly different from an interactive (SQL*Plus) version. Every embedded SQL statement begins with EXEC SQL. The colon, :, precedes every host (COBOL) variable. The SQL statement is terminated by END-EXEC. The returned values of data and indicators (set when the data value is NULL or character columns have been truncated) can be stored in group items (such as in the above code fragment), in tables, or in tables of group items. Multiple result set values are handled very simply in a manner that resembles the case shown, where there is only one result, given the unique employee number. You use the actual names of columns and tables in embedded SQL. Use the default precompiler option values, or you can enter values which give you control over the use of resources, how errors are reported, the formatting of output, and how cursors (which correspond to a particular connection or SQL statement) are managed. Enter the options either in a conguration le, on the command line, or inline inside your source code with a special statement that begins with EXEC ORACLE. If there are no errors found, you can then compile, link, and execute the output source le, like any other COBOL program that you write. Use the precompiler to create server database access from clients that can be on many different platforms. Pro*COBOL allows you the freedom to design your own user interfaces and to add database access to existing COBOL applications. The embedded SQL statements available conform to an ANSI standard, so that you can access data from many databases in a program, including remote servers networked through Oracle Net. Before writing your embedded SQL statements, you may want to test interactive versions of the SQL in SQL*Plus. You then make only minor changes to start testing your embedded SQL application.
1-25
Improved performance and scalability through the efcient use of system memory and network connectivity Consistent interfaces for dynamic session and transaction management in a two-tier client/server or multitier environment N-tiered authentication Comprehensive support for application development using Oracle objects Access to external databases
1-26
Ability to develop applications that service an increasing number of users and requests without additional hardware investments
OCI lets you manipulate data and schemas in an Oracle database using a host programming language, such as C. OCCI is an object-oriented interface suitable for use with C++. These APIs provide a library of standard database access and retrieval functions in the form of a dynamic runtime library (OCILIB) that can be linked in an application at runtime. This eliminates the need to embed SQL or PL/SQL within 3GL programs. For more information about the OCI and OCCI calls, see Oracle Call Interface Programmers Guide, Oracle C++ Call Interface Programmers Guide, Oracle9i Application Developers Guide - Advanced Queuing, Oracle9i Globalization and National Language Support Guide, and Oracle9i Data Cartridge Developers Guide.
Advantages of OCI
OCI provides signicant advantages over other methods of accessing an Oracle database:
s
More ne-grained control over all aspects of the application design. High degree of control over program execution. Use of familiar 3GL programming techniques and application development tools such as browsers and debuggers. Support of dynamic SQL,method 4. Availability on the broadest range of platforms of all the Oracle programmatic interfaces. Dynamic bind and dene using callbacks. Describe functionality to expose layers of server metadata. Asynchronous event notication for registered client applications. Enhanced array data manipulation language (DML) capability for array INSERTs, UPDATEs, and DELETEs. Ability to associate a commit request with an execute to reduce round-trips. Optimization for queries using transparent prefetch buffers to reduce round-trips. Thread safety so you do not have to use mutual exclusive locks (mutex) on OCI handles.
1-27
The server connection in nonblocking mode means that control returns to the OCI code when a call is still executing or could not complete.
OCI relational functions, for managing database access and processing SQL statements OCI navigational functions, for manipulating objects retrieved from an Oracle database server OCI datatype mapping and manipulation functions, for manipulating data attributes of Oracle types OCI external procedure functions, for writing C callbacks from PL/SQL
In a non-procedural language program, the set of data to be operated on is specied, but what operations will be performed, or how the operations are to be carried out is not specied. The non-procedural nature of SQL makes it an easy language to learn and to use to perform database transactions. It is also the standard language used to access and manipulate data in modern relational and object-relational database systems. In a procedural language program, the execution of most statements depends on previous or subsequent statements and on control structures, such as loops or conditional branches, which are not available in SQL. The procedural nature of these languages makes them more complex than SQL, but it also makes them very exible and powerful.
The combination of both non-procedural and procedural language elements in an OCI program provides easy access to an Oracle database in a structured programming environment. The OCI supports all SQL data denition, data manipulation, query, and transaction control facilities that are available through an Oracle database server. For example, an OCI program can run a query against an Oracle database. The
1-28
queries can require the program to supply data to the database using input (bind) variables, as follows:
SELECT name FROM employees WHERE empno = :empnumber
In the above SQL statement,:empnumber is a placeholder for a value that will be supplied by the application. You can also use PL/SQL, Oracles procedural extension to SQL. The applications you develop can be more powerful and exible than applications written in SQL alone. The OCI also provides facilities for accessing and manipulating objects in an Oracle database server.
1-29
Source Files
Object Files
OCI Library
Host Linker
Application
Oracle Server
Note: On some platforms, it may be necessary to include other libraries, in addition to the OCI library, to properly link your OCI programs. Check your Oracle system-specic documentation for further information about extra libraries that may be required.
1-30
OO4O "In-Process" Automation Server Oracle Data Control Oracle Objects for OLE C++ Class Library
COM/DCOM OO4O In-Process Automation Server Oracle Client Libraries (OCI, CORE, NLS)
Oracle Database
Note: See the OO4O online help for detailed information about using OO4O.
1-31
Support for execution of PL/SQL and Java stored procedures, and PL/SQL anonymous blocks. This includes support for Oracle datatypes used as parameters to stored procedures, including PL/SQL cursors. See "Support for Oracle LOB and Object Datatypes" on page 1-37. Support for scrollable and updatable cursors for easy and efcient access to result sets of queries. Thread-safe objects and Connection Pool Management Facility for developing efcient web server applications. Full support for Oracle object-relational and LOB datatypes. Full support for Advanced Queuing. Support for array inserts and updates. Support for Microsoft Transaction Server (MTS).
1-32
OraSession
OraServer
OraDatabase
OraSQLStmt
OraField
OraDynaset
OraParameter
OraParameters
OraParameterArray
OraMetaData
OraMDAttribute
OraAQ
OraAQMsg
OraSession
An OraSession object manages collections of OraDatabase, OraConnection, and OraDynaset objects used within an application. Typically, a single OraSession object is created for each application, but you can create named OraSession objects for shared use within and between applications. The OraSession object is the top-most level object for an application. It is the only object created by the CreateObject VB/VBA API and not by an Oracle Objects for OLE method. The following code fragment shows how to create an OraSession object:
Dim OraSession as Object Set OraSession = CreateObject("OracleInProcServer.XOraSession")
OraServer
OraServer represents a physical network connection to an Oracle database server.
1-33
The OraServer interface is introduced to expose the connection multiplexing feature provided in the Oracle Call Interface. After an OraServer object is created, multiple user sessions (OraDatabase) can be attached to it by invoking the OpenDatabase method. This feature is particularly useful for application components, such as Internet Information Server (IIS), that use Oracle Objects for OLE in an n-tier distributed environments. The use of connection multiplexing when accessing Oracle severs with a large number of user sessions active can help reduce server processing and resource requirements while improving the server scalability.
OraDatabase
An OraDatabase interface adds additional methods for controlling transactions and creating interfaces representing of Oracle object types. Attributes of schema objects can be retrieved using the Describe method of the OraDatabase interface. In older releases, an OraDatabase object is created by invoking the OpenDatabase method of an OraSession interface. The Oracle Net alias, user name, and password are passed as arguments to this method. In Oracle8i and later, invocation of this method results in implicit creation of an OraServer object. As described in the OraServer interface description, an OraDatabase object can also be created using the OpenDatabase method of the OraServer interface. Transaction control methods are available at the OraDatabase (user session) level. Transactions may be started as Read-Write (default), Serializable, or Read-only. These include:
s
For example:
UserSession.BeginTrans(OO4O_TXN_READ_WRITE) UserSession.ExecuteSQL("delete emp where empno = 1234") UserSession.CommitTrans
OraDynaset
An OraDynaset object permits browsing and updating of data created from a SQL SELECT statement.
1-34
The OraDynaset object can be thought of as a cursor, although in actuality several real cursors may be used to implement the OraDynaset's semantics. An OraDynaset automatically maintains a local cache of data fetched from the server and transparently implements scrollable cursors within the browse data. Large queries may require signicant local disk space; application implementers are encouraged to rene queries to limit disk usage.
OraField
An OraField object represents a single column or data item within a row of a dynaset. If the current row is being updated, then the OraField object represents the currently updated value, although the value may not yet have been committed to the database. Assignment to the Value property of a eld is permitted only if a record is being edited (using Edit) or a new record is being added (using AddNew). Other attempts to assign data to a eld's Value property results in an error.
OraMetaData
An OraMetaData object is a collection of OraMDAttribute objects that represent the description information about a particular schema object in the database. The OraMetaData object can be visualized as a table with three columns:
s
Metadata Attribute Name Metadata Attribute Value Flag specifying whether the Value is another OraMetaData Object
The OraMDAttribute objects contained in the OraMetaData object can be accessed by subscripting using ordinal integers or by using the name of the property. Referencing a subscript that is not in the collection (0 to Count-1) results in the return of a NULL OraMDAttribute object.
OraParameter
An OraParameter object represents a bind variable in a SQL statement or PL/SQL block. OraParameter objects are created, accessed, and removed indirectly through the OraParameters collection of an OraDatabase object. Each parameter has an identifying name and an associated value. You can automatically bind a parameter
1-35
to SQL and PL/SQL statements of other objects (as noted in the objects descriptions), by using the parameters name as a placeholder in the SQL or PL/SQL statement. Such use of parameters can simplify dynamic queries and increase program performance.
OraParamArray
An OraParamArray object represents an "array" type bind variable in a SQL statement or PL/SQL block as opposed to a "scalar" type bind variable represented by the OraParameter object. OraParamArray objects are created, accessed, and removed indirectly through the OraParameters collection of an OraDatabase object. Each parameter has an identifying name and an associated value.
OraSQLStmt
An OraSQLStmt Object represents a single SQL statement. Use the CreateSQL method to create the OraSQLStmt object from an OraDatabase. During create and refresh, OraSQLStmt objects automatically bind all relevant, enabled input parameters to the specied SQL statement, using the parameter names as placeholders in the SQL statement. This can improve the performance of SQL statement execution without re-parsing the SQL statement.
SQLStmt
The SQLStmt object (updateStmt) can be later used to execute the same query using a different value for the :SALARY placeholder. This is done as follows:
OraDatabase.Parameters("SALARY").value = 200000 updateStmt.Parameters("ENAME").value = "KING" updateStmt.Refresh
OraAQ
An OraAQ object is instantiated by invoking the CreateAQ method of the OraDatabase interface. It represents a queue that is present in the database. Oracle Objects for OLE provides interfaces for accessing Oracles Advanced Queuing (AQ) Feature. It makes AQ accessible from popular COM-based development environments such as Visual Basic. For a detailed description of Oracle AQ, please refer to Oracle9i Application Developers Guide - Advanced Queuing.
1-36
OraAQMsg
The OraAQMsg object encapsulates the message to be enqueued or dequeued. The message can be of any user-dened or raw type. For a detailed description of Oracle AQ, please refer to Oracle9i Application Developers Guide - Advanced Queuing.
OraAQAgent
The OraAQAgent object represents a message recipient and is only valid for queues which allow multiple consumers. The OraAQAgent object represents a message recipient and is only valid for queues which allow multiple consumers. An OraAQAgent object can be instantiated by invoking the AQAgent method. For example:
Set agent = qMsg.AQAgent(name)
An OraAQAgent object can also be instantiated by invoking the AddRecipient method. For example:
Set agent = qMsg.AddRecipient(name, address, protocol).
1-37
OraObject
OraAttribute
OraField
OraRef
OraAttribute
OraParameter
OraCollection
Element Values
OraBLOB
OraCLOB
OraBFILE
OraBFILE
The OraBFile interface in OO4O provides methods for performing operations on large objects BFILE data type in the database. The BFILEs are large binary data objects stored in operating system les (external) outside of the database tablespaces.
1-38
Oracle Objects for OLE Help Oracle Objects for OLE C++ Class Library Help
To view examples of the use of Oracle Object for OLE, see the samples located in the ORACLE_HOME\OO4O directory of the Oracle installation. Additional OO4O examples can be found in the following Oracle publications, including:
s
Oracle9i Application Developers Guide - Large Objects (LOBs) Oracle9i Application Developers Guide - Advanced Queuing Oracle9i Supplied PL/SQL Packages and Types Reference
1-39
Review the preceding overviews and the manuals for each environment. Read the platform-specic manual that explains which compilers are approved for use with your platforms. If a particular language does not provide a feature you need, remember that PL/SQL and Java stored procedures can both be called from code written in any of the languages in this chapter. Stored procedures include triggers and object type methods. External procedures written in C can be called from OCI, Java, PL/SQL or SQL. The external procedure itself can call back into the database using either SQL, OCI, or Pro*C (but not C++).
Pro*COBOL does not support object types or collection types, while Pro*C/C++ does. SQLJ does not support dynamic SQL the way that JDBC does.
OCI provides more detailed control over multiplexing and migrating sessions. OCI provides dynamic bind and dene using callbacks that can be used for any arbitrary structure, including lists. OCI has many calls to handle metadata. OCI allows asynchronous event notications to be received by a client application. It provides a means for clients to generate notications for propagation to other clients. OCI allows DML statements to use arrays to complete as many iterations as possible and then return a batch of errors.
1-40
OCI calls for special purposes include Advanced Queuing, globalization support, Data Cartridges, and support of the date and time datatypes. OCI calls can be embedded in a Pro*C/C++ application.
1-41
1-42
Part II
Designing the Database
This part contains the following chapters:
s
Chapter 2, "Managing Schema Objects" Chapter 3, "Selecting a Datatype" Chapter 4, "Maintaining Data Integrity Through Constraints" Chapter 5, "Selecting an Index Strategy" Chapter 6, "Speeding Up Index Access with Index-Organized Tables" Chapter 7, "How Oracle Processes SQL Statements" Chapter 8, "Coding Dynamic SQL Statements" Chapter 9, "Using Procedures and Packages" Chapter 10, "Calling External Procedures"
2
Managing Schema Objects
This chapter discusses the procedures necessary to create and manage the different types of objects contained in a users schema. The topics include:
s
Managing Tables Managing Temporary Tables Managing Views Modifying a Join View Managing Sequences Managing Synonyms Creating Multiple Tables and Views in One Operation Naming Schema Objects Renaming Schema Objects Listing Information about Schema Objects
Managing Tables
See Also:
s
Indexes and clusters Chapter 5, "Selecting an Index Strategy" Procedures, functions, and packages Chapter 9, "Using Procedures and Packages" Object types Oracle9i Application Developers Guide Object-Relational Features Dependency information Chapter 9, "Using Procedures and Packages" If you use symmetric replication, then see Oracle9i Replication for information on managing schema objects, such as snapshots.
Managing Tables
A table is the data structure that holds data in a relational database. A table is composed of rows and columns. A table can represent a single entity that you want to track within your system. This type of a table could represent a list of the employees within your organization, or the orders placed for your companys products. A table can also represent a relationship between two entities. This type of a table could portray the association between employees and their job skills, or the relationship of products to orders. Within the tables, foreign keys are used to represent relationships. Although some well designed tables could represent both an entity and describe the relationship between that entity and another entity, most tables should represent either an entity or a relationship. For example, the EMP_TAB table describes the employees in a rm, but this table also includes a foreign key column, DEPTNO, representing the relationships of employees to departments. The following sections explain how to create, alter, and drop tables. Some simple guidelines to follow when managing tables in your database are included.
See Also: The Oracle9i Database Administrators Guide has more
suggestions. You should also refer to a text on relational database or table design.
2-2
Managing Tables
Designing Tables
Consider the following guidelines when designing your tables:
s
Use descriptive names for tables, columns, indexes, and clusters. Be consistent in abbreviations and in the use of singular and plural forms of table names and columns. Document the meaning of each table and its columns with the COMMENT command. Normalize each table. Select the appropriate datatype for each column. Dene columns that allow nulls last, to conserve storage space. Cluster tables whenever appropriate, to conserve storage space and optimize performance of SQL statements.
Before creating a table, you should also determine whether to use integrity constraints. Integrity constraints can be dened on the columns of a table to enforce the business rules of your database automatically.
See Also:
s
Oracle9i Database Administrators Guide for guidelines about tables and general guidelines for managing the space used by schema objects. Chapter 3, "Selecting a Datatype" for information about datatypes. Chapter 4, "Maintaining Data Integrity Through Constraints" for guidelines on integrity constraints.
s s
Creating Tables
To create a table, use the SQL command CREATE TABLE. For example, the following statement creates a non-clustered table named Emp_tab that is physically stored in the USERS tablespace. Notice that integrity constraints are dened on several columns of the table.
CREATE TABLE Empno Ename Job Mgr Hiredate Sal Comm Emp_tab ( NUMBER(5) PRIMARY KEY, VARCHAR2(15) NOT NULL, VARCHAR2(10), NUMBER(5), DATE DEFAULT (sysdate), NUMBER(7,2), NUMBER(7,2),
Deptno
PCTFREE 10 PCTUSED 40 TABLESPACE users STORAGE ( INITIAL 50K NEXT 50K MAXEXTENTS 10 PCTINCREASE 25 );
A Web-based airlines reservations application allows a customer to create several optional itineraries. Each itinerary is represented by a row in a temporary table. The application updates the rows to reect changes in the itineraries. When the customer decides which itinerary you want to use, the application moves the row for that itinerary to a persistent table. During the session, the itinerary data is private. At the end of the session, the optional itineraries are dropped.
Several sales agents for a large bookseller use a single temporary table concurrently while taking customer orders over the phone. To enter and modify customer orders, each agent accesses the table in a session that is unavailable to the other agents. When the agent closes a session, the data from that session is automatically dropped, but the table structure persists for the other agents to use. An administrator uses temporary tables to improve performance when running an otherwise complex and expensive query. To do this, the administrator caches the values from a more complex query in temporary tables, then runs SQL statements, such as joins, against those temporary tables. For a thorough explanation of how this can be done, see "Example: Using Temporary Tables to Improve Performance" on page 2-6.
2-4
You cannot create a table that is simultaneously both transaction- and session-specic. A transaction-specic temporary table allows only one transaction at a time. If there are several autonomous transactions in a single transaction scope, each autonomous transaction can use the table only as soon as the previous one commits. Because the data in a temporary table is, by denition, temporary, backup and recovery of a temporary tables data is not available in the event of a system failure. To prepare for such a failure, you should develop alternative methods for preserving temporary table data.
2-6
(Level_code = 'DEPARTMENT' AND Level_id = U.Department_id) OR (Level_code = 'SITE')) AND NOT EXISTS (SELECT 1 FROM PROFILE_VALUES P WHERE P.PROFILE_OPTION_ID = V.PROFILE_OPTION_ID AND ((Level_code = 'USER' AND level_id = u.User_id) OR (Level_code = 'DEPARTMENT' AND level_id = u.Department_id) OR (Level_code = 'SITE')) AND INSTR('USERDEPARTMENTSITE', v.Level_code) > INSTR('USERDEPARTMENTSITE', p.Level_code));
A temporary table allows us to run the computation once, and cache the result in later SQL queries and joins:
CREATE GLOBAL TEMPORARY TABLE Profile_values_temp ( Profile_option_name VARCHAR(60) NOT NULL, Profile_option_id NUMBER(4) NOT NULL, Profile_option_value VARCHAR2(20) NOT NULL, Level_code VARCHAR2(10) , Level_id NUMBER(4) , CONSTRAINT Profile_values_temp_pk PRIMARY KEY (Profile_option_id) ) ON COMMIT PRESERVE ROWS ORGANIZATION INDEX; INSERT INTO Profile_values_temp (Profile_option_name, Profile_option_id, Profile_option_value, Level_code, Level_id) SELECT Profile_option_name, Profile_option_id, Profile_option_value, Level_code, Level_id FROM Profile_values_view; COMMIT;
Now the temporary table can be used to speed up queries, and the results cached in the temporary table are freed automatically by the database when the session ends.
This technique lets the optimizer choose how to deal with the subquery results -whether to create a temporary table or inline it as a view. For example, the following query joins two tables and computes the aggregate SUM(SAL) more than once. The bold text represents the parts of the query that are repeated.
SELECT dname, SUM(sal) AS dept_total FROM emp, dept WHERE emp.deptno = dept.deptno GROUP BY dname HAVING SUM(sal) > ( SELECT SUM(sal) * 1/3 FROM emp, dept WHERE emp.deptno = dept.deptno ) ORDER BY SUM(sal) DESC;
You can improve the query by doing the subquery once, and referencing it at the appropriate points in the main query. The bold text represents the common parts of the subquery, and the places where the subquery is referenced.
WITH summary AS ( SELECT dname, SUM(sal) AS dept_total FROM emp, dept WHERE emp.deptno = dept.deptno GROUP BY dname ) SELECT dname, dept_total FROM summary WHERE dept_total > ( SELECT SUM(dept_total) * 1/3 FROM summary ) ORDER BY dept_total DESC;
2-8
Managing Views
See Also:
s s
Oracle9i SQL Reference for the full syntax of the WITH clause. Oracle9i Database Performance Guide and Reference for techniques to use this feature to improve performance.
Managing Views
A view is a logical representation of another table or combination of tables. A view derives its data from the tables on which it is based. These tables are called base tables. Base tables might in turn be actual tables or might be views themselves. All operations performed on a view actually affect the base table of the view. You can use views in almost the same way as tables. You can query, update, insert into, and delete from views, just as you can standard tables. Views can provide a different representation (such as subsets or supersets) of the data that resides within other tables and views. Views are very powerful because they allow you to tailor the presentation of data to different types of users. The following sections explain how to create, replace, and drop views using SQL commands.
Creating Views
Use the SQL command CREATE VIEW to create a view. For example, the following statement creates a view on a subset of data in the EMP_TAB table:
CREATE VIEW Sales_staff AS SELECT Empno, Ename, Deptno FROM Emp_tab WHERE Deptno = 10 WITH CHECK OPTION CONSTRAINT Sales_staff_cnst;
The object names are resolved when the view is created or when the program containing the SQL is compiled, relative to the schema of the view owner. You can dene views with any query that references tables, snapshots, or other views. The query that denes the SALES_STAFF view references only rows in department 10. Furthermore, WITH CHECK OPTION creates the view with the constraint that INSERT and UPDATE statements issued against the view are not allowed to create or result in rows that the view cannot select.
Managing Views
Considering the example above, the following INSERT statement successfully inserts a row into the EMP_TAB table through the SALES_STAFF view:
INSERT INTO Sales_staff VALUES (7584, OSTER, 10);
However, the following INSERT statement is rolled back and returns an error because it attempts to insert a row for department number 30, which could not be selected using the SALES_STAFF view:
INSERT INTO Sales_staff VALUES (7591, WILLIAMS, 30);
The following statement creates a view that joins data from the Emp_tab and Dept_tab tables:
CREATE VIEW Division1_staff AS SELECT Ename, Empno, Job, Dname FROM Emp_tab, Dept_tab WHERE Emp_tab.Deptno IN (10, 30) AND Emp_tab.Deptno = Dept_tab.Deptno;
The Division1_staff view is dened by a query that joins information from the Emp_tab and Dept_tab tables. The WITH CHECK OPTION is not specied in the CREATE VIEW statement because rows cannot be inserted into or updated in a view dened with a query that contains a join that uses the WITH CHECK OPTION.
Views created with errors do not have wildcards expanded. However, if the view is eventually compiled without errors, then wildcards in the dening query are expanded.
2-10
Managing Views
When a view is created with errors, Oracle returns a message and leaves the status of the view as INVALID. If conditions later change so that the query of an invalid view can be executed, then the view can be recompiled and become valid. Oracle dynamically compiles the invalid view if you attempt to use it.
You must have the CREATE VIEW system privilege to create a view in your schema, or the CREATE ANY VIEW system privilege to create a view in another users schema. These privileges can be acquired explicitly or through a role. The owner of the view must be explicitly granted the necessary privileges to access all objects referenced within the denition of the view; the owner cannot obtain the required privileges through roles. Also, the functionality of the view is dependent on the privileges of the views owner. For example, if you (the view owner) are granted only the INSERT privilege for Scotts EMP_TAB table, then you can create a view on his EMP_TAB table, but you can only use this view to insert new rows into the EMP_TAB table. If the view owner intends to grant access to the view to other users, then the owner must receive the object privileges to the base objects with the GRANT OPTION or the system privileges with the ADMIN OPTION; if not, then the view owner has insufcient privileges to grant access to the view to other users.
Replacing Views
To alter the denition of a view, you must replace the view using one of the following methods:
Managing Views
A view can be dropped and then re-created. When a view is dropped, all grants of corresponding view privileges are revoked from roles and users. After the view is re-created, necessary privileges must be regranted. A view can be replaced by redening it with a CREATE VIEW statement that contains the OR REPLACE option. This option replaces the current denition of a view, but preserves the present security authorizations. For example, assume that you create the SALES_STAFF view, as given in a previous example. You also grant several object privileges to roles and other users. However, now you realize that you must redene the SALES_STAFF view to correct the department number specied in the WHERE clause of the dening query, because it should have been 30. To preserve the grants of object privileges that you have made, you can replace the current version of the SALES_STAFF view with the following statement:
CREATE OR REPLACE VIEW Sales_staff AS SELECT Empno, Ename, Deptno FROM Emp_tab WHERE Deptno = 30 WITH CHECK OPTION CONSTRAINT Sales_staff_cnst;
Replacing a view replaces the views denition in the data dictionary. All underlying objects referenced by the view are not affected. If previously dened but not included in the new view denition, then the constraint associated with the WITH CHECK OPTION for a views denition is dropped. All views and PL/SQL program units dependent on a replaced view become invalid.
2-12
Managing Views
ENAME EMPNO JOB DNAME -----------------------------------------------------CLARK 7782 MANAGER ACCOUNTING KING 7839 PRESIDENT ACCOUNTING MILLER 7934 CLERK ACCOUNTING ALLEN 7499 SALESMAN SALES WARD 7521 SALESMAN SALES JAMES 7900 CLERK SALES TURNER 7844 SALESMAN SALES MARTIN 7654 SALESMAN SALES BLAKE 7698 MANAGER SALES
With some restrictions, rows can be inserted into, updated in, or deleted from a base table using a view. The following statement inserts a new row into the EMP_TAB table using the SALES_STAFF view:
INSERT INTO Sales_staff VALUES (7954, OSTER, 30);
Restrictions on DML operations for views use the following criteria in the order listed:
1.
If a view is dened by a query that contains SET or DISTINCT operators, a GROUP BY clause, or a group function, then rows cannot be inserted into, updated in, or deleted from the base tables using the view. If a view is dened with WITH CHECK OPTION, then a row cannot be inserted into, or updated in, the base table (using the view), if the view cannot select the row from the base table. If a NOT NULL column that does not have a DEFAULT clause is omitted from the view, then a row cannot be inserted into the base table using the view. If the view was created by using an expression, such as DECODE(deptno, 10, "SALES", ...), then rows cannot be inserted into or updated in the base table using the view.
2.
3. 4.
The constraint created by WITH CHECK OPTION of the SALES_STAFF view only allows rows that have a department number of 10 to be inserted into, or updated in, the EMP_TAB table. Alternatively, assume that the SALES_STAFF view is dened by the following statement (that is, excluding the DEPTNO column):
CREATE VIEW Sales_staff AS SELECT Empno, Ename FROM Emp_tab WHERE Deptno = 10
Managing Views
Considering this view denition, you can update the EMPNO or ENAME elds of existing records, but you cannot insert rows into the EMP_TAB table through the SALES_STAFF view because the view does not let you alter the DEPTNO eld. If you had dened a DEFAULT value of 10 on the DEPTNO eld, then you could perform inserts. Referencing Invalid Views When a user attempts to reference an invalid view, Oracle returns an error message to the user:
ORA-04063: view view_name has errors
This error message is returned when a view exists but is unusable due to errors in its query (whether it had errors when originally created or it was created successfully but became unusable later because underlying objects were altered or dropped).
Dropping Views
Use the SQL command DROP VIEW to drop a view. For example:
DROP VIEW Sales_staff;
2-14
This view does not involve a join operation. If you issue the SQL statement:
UPDATE Emp_view SET Ename = CAESAR WHERE Empno = 7839;
then the EMP_TAB base table that underlies the view changes, and employee 7839s name changes from KING to CAESAR in the EMP_TAB table. However, if you create a view that involves a join operation, such as:
CREATE VIEW Emp_dept_view AS SELECT e.Empno, e.Ename, e.Deptno, e.Sal, d.Dname, d.Loc FROM Emp_tab e, Dept_tab d /* JOIN operation */ WHERE e.Deptno = d.Deptno AND d.Loc IN (DALLAS, NEW YORK, BOSTON);
then there are restrictions on modifying either the EMP_TAB or the DEPT_TAB base table through this view, for example, using a statement such as:
UPDATE Emp_dept_view SET Ename = JOHNSON WHERE Ename = SMITH;
A modiable join view is a view that contains more than one table in the top-level FROM clause of the SELECT statement, and that does not contain any of the following:
s
DISTINCT operator Aggregate functions: AVG, COUNT, GLB, MAX, MIN, STDDEV, SUM, or VARIANCE Set operations: UNION, UNION ALL, INTERSECT, MINUS GROUP BY or HAVING clauses START WITH or CONNECT BY clauses ROWNUM pseudocolumn
A further restriction on which join views are modiable is that if a view is a join on other nested views, then the other nested views must be mergeable into the top level view.
See Also:
Oracle9i Database Concepts for more information about mergeable views. "Modifying Complex Views (INSTEAD OF Triggers)" on page 15-7 for a way to simulate updating a join view by writing a customized trigger.
You could also omit the primary and foreign key constraints listed above, and create a UNIQUE INDEX on DEPT_TAB (DEPTNO) to make the following examples work.
2-16
Note:
s
It is not necessary that the key or keys of a table be selected for it to be key preserved. It is sufcient that if the key or keys were selected, then they would also be key(s) of the result of the join. The key-preserving property of a table does not depend on the actual data in the table. It is, rather, a property of its schema and not of the data in the table. For example, if in the EMP_TAB table there was at most one employee in each department, then DEPT_TAB.DEPTNO would be unique in the result of a join of EMP_TAB and DEPT_TAB, but DEPT_TAB would still not be a key-preserved table.
If you SELECT all rows from EMP_DEPT_VIEW dened in the "Modifying a Join View" section, then the results are:
EMPNO ENAME DEPTNO DNAME LOC --------------------------------------------------------7782 CLARK 10 ACCOUNTING NEW YORK 7839 KING 10 ACCOUNTING NEW YORK 7934 MILLER 10 ACCOUNTING NEW YORK 7369 SMITH 20 RESEARCH DALLAS 7876 ADAMS 20 RESEARCH DALLAS 7902 FORD 20 RESEARCH DALLAS 7788 SCOTT 20 RESEARCH DALLAS 7566 JONES 20 RESEARCH DALLAS 8 rows selected.
In this view, EMP_TAB is a key-preserved table, because EMPNO is a key of the EMP_TAB table, and also a key of the result of the join. DEPT_TAB is not a key-preserved table, because although DEPTNO is a key of the DEPT_TAB table, it is not a key of the join.
This statement fails with an ORA-01779 error ("cannot modify a column which maps to a non key-preserved table"), because it attempts to modify the underlying DEPT_TAB table, and the DEPT_TAB table is not key preserved in the EMP_DEPT view. In general, all modiable columns of a join view must map to columns of a key-preserved table. If the view is dened using the WITH CHECK OPTION clause, then all join columns and all columns of repeated tables are not modiable. So, for example, if the EMP_DEPT view were dened using WITH CHECK OPTION, then the following UPDATE statement would fail:
UPDATE Emp_dept_view SET Deptno = 10 WHERE Ename = SMITH;
This DELETE statement on the EMP_DEPT view is legal because it can be translated to a DELETE operation on the base EMP_TAB table, and because the EMP_TAB table is the only key-preserved table in the join.
2-18
In the following view, a DELETE operation cannot be performed on the view because both E1 and E2 are key-preserved tables:
CREATE VIEW emp_emp AS SELECT e1.Ename, e2.Empno, e1.Deptno FROM Emp_tab e1, Emp_tab e2 WHERE e1.Empno = e2.Empno; WHERE e1.Empno = e2.Empno;
If a view is dened using the WITH CHECK OPTION clause and the key-preserved table is repeated, then rows cannot be deleted from such a view. For example:
CREATE VIEW Emp_mgr AS SELECT e1.Ename, e2.Ename Mname FROM Emp_tab e1, Emp_tab e2 WHERE e1.mgr = e2.Empno WITH CHECK OPTION;
No deletion can be performed on this view because the view involves a self-join of the table that is key preserved.
The following INSERT statement fails for the same reason: This UPDATE on the base EMP_TAB table would fail: the FOREIGN KEY integrity constraint on the EMP_TAB table is violated.
INSERT INTO Emp_dept (Ename, Empno, Deptno) VALUES (KURODA, 9010, 77);
The following INSERT statement fails with an ORA-01776 error ("cannot modify more than one base table through a view").
INSERT INTO Emp_dept (Ename, Empno, Deptno) VALUES (9010, KURODA, BOSTON);
An INSERT cannot, implicitly or explicitly, refer to columns of a non-key-preserved table. If the join view is dened using the WITH CHECK OPTION clause, then you cannot perform an INSERT to it.
USER_UPDATABLE_COLUMNS Shows all columns in all tables and views in the users schema that are modiable DBA_UPDATABLE_COLUMNS ALL_UPDATABLE_COLUMNS Shows all columns in all tables and views in the DBA schema that are modiable Shows all columns in all tables and views that are modiable
Outer Joins
Views that involve outer joins are modiable in some cases. For example:
CREATE VIEW Emp_dept_oj1 AS SELECT Empno, Ename, e.Deptno, Dname, Loc FROM Emp_tab e, Dept_tab d WHERE e.Deptno = d.Deptno (+);
The statement:
SELECT * FROM Emp_dept_oj1;
Results in:
EMPNO ------7369 7499 7566 7654 7698 7782 7788 7839 7844 ENAME ---------SMITH ALLEN JONES MARTIN BLAKE CLARK SCOTT KING TURNER DEPTNO ------40 30 20 30 30 10 20 10 30 DNAME -------------OPERATIONS SALES RESEARCH SALES SALES ACCOUNTING RESEARCH ACCOUNTING SALES LOC ------------BOSTON CHICAGO DALLAS CHICAGO CHICAGO NEW YORK DALLAS NEW YORK CHICAGO
2-20
20 30 20 10 30
Columns in the base EMP_TAB table of EMP_DEPT_OJ1 are modiable through the view, because EMP_TAB is a key-preserved table in the join. The following view also contains an outer join:
CREATE VIEW Emp_dept_oj2 AS SELECT e.Empno, e.Ename, e.Deptno, d.Dname, d.Loc FROM Emp_tab e, Dept_tab d WHERE e.Deptno (+) = d.Deptno;
The statement:
SELECT * FROM Emp_dept_oj2;
Results in:
EMPNO ---------7782 7839 7934 7369 7876 7902 7788 7566 7499 7698 7654 7900 7844 7521 ENAME ---------CLARK KING MILLER SMITH ADAMS FORD SCOTT JONES ALLEN BLAKE MARTIN JAMES TURNER WARD DEPTNO --------10 10 10 20 20 20 20 20 30 30 30 30 30 30 DNAME -------------ACCOUNTING ACCOUNTING ACCOUNTING RESEARCH RESEARCH RESEARCH RESEARCH RESEARCH SALES SALES SALES SALES SALES SALES OPERATIONS LOC ---NEW YORK NEW YORK NEW YORK DALLAS DALLAS DALLAS DALLAS DALLAS CHICAGO CHICAGO CHICAGO CHICAGO CHICAGO CHICAGO BOSTON
15 rows selected.
In this view, EMP_TAB is no longer a key-preserved table, because the EMPNO column in the result of the join can have nulls (the last row in the SELECT above). So, UPDATE, DELETE, and INSERT operations cannot be performed on this view.
In the case of views containing an outer join on other nested views, a table is key preserved if the view or views containing the table are merged into their outer views, all the way to the top. A view which is being outer-joined is currently merged only if it is "simple." For example:
SELECT Col1, Col2, ... FROM T;
The select list of the view has no expressions, and there is no WHERE clause. Consider the following set of views:
CREATE VIEW Emp_v AS SELECT Empno, Ename, Deptno FROM Emp_tab; CREATE VIEW Emp_dept_oj1 AS SELECT e.*, Loc, d.Dname FROM Emp_v e, Dept_tab d WHERE e.Deptno = d.Deptno (+);
In these examples, EMP_V is merged into EMP_DEPT_OJ1 because EMP_V is a simple view, and so EMP_TAB is a key-preserved table. But if EMP_V is changed as follows:
CREATE VIEW Emp_v_2 AS SELECT Empno, Ename, Deptno FROM Emp_tab WHERE Sal > 1000;
Then, because of the presence of the WHERE clause, EMP_V_2 cannot be merged into EMP_DEPT_OJ1, and hence EMP_TAB is no longer a key-preserved table. If you are in doubt whether a view is modiable, then you can SELECT from the view USER_UPDATABLE_COLUMNS to see if it is. For example:
SELECT * FROM USER_UPDATABLE_COLUMNS WHERE TABLE_NAME = EMP_DEPT_VIEW;
2-22
Managing Sequences
Managing Sequences
The sequence generator generates sequential numbers, which can help to generate unique primary keys automatically, and to coordinate keys across multiple rows or tables. Without sequences, sequential values can only be produced programmatically. A new primary key value can be obtained by selecting the most recently produced value and incrementing it. This method requires a lock during the transaction and causes multiple users to wait for the next value of the primary key; this waiting is known as serialization. If you have such constructs in your applications, then you should replace them with access to sequences. Sequences eliminate serialization and improve the concurrency of your application. The following sections explain how to create, alter, use, and drop sequences using SQL commands.
Creating Sequences
Use the SQL command CREATE SEQUENCE to create a sequence. The following statement creates a sequence used to generate employee numbers for the EMPNO column of the EMP_TAB table:
CREATE SEQUENCE Emp_sequence INCREMENT BY 1 START WITH 1 NOMAXVALUE NOCYCLE CACHE 10;
Notice that several parameters can be specied to control the function of sequences. You can use these parameters to indicate whether the sequence is ascending or descending, the starting point of the sequence, the minimum and maximum values, and the interval between sequence values. The NOCYCLE option indicates that the sequence cannot generate more values after reaching its maximum or minimum value. The CACHE option of the CREATE SEQUENCE command pre-allocates a set of sequence numbers and keeps them in memory so that they can be accessed faster. When the last of the sequence numbers in the cache have been used, another set of numbers is read into the cache.
Managing Sequences
numbers when using Oracle Real Application Clusters, see Oracle9i Parallel Server Documentation Set: Oracle8i Parallel Server Concepts; Oracle8i Parallel Server Setup and Conguration Guide; Oracle8i Parallel Server Administration, Deployment, and Performance. General information about caching sequence numbers is included in "Caching Sequence Numbers" on page 2-27.
Altering Sequences
You can change any of the parameters that dene how corresponding sequence numbers are generated; however, you cannot alter a sequence to change the starting number of a sequence. To do this, you must drop and re-create the sequence. Use the SQL command ALTER SEQUENCE to alter a sequence. For example:
ALTER SEQUENCE Emp_sequence INCREMENT BY 10 MAXVALUE 10000 CYCLE CACHE 20;
Using Sequences
Once a sequence is dened, it can be accessed and incremented by multiple users with no waiting. Oracle does not wait for a transaction that has incremented a sequence to complete before that sequence can be incremented again. The examples outlined in the following sections show how sequences can be used in master/detail table relationships. Assume an order entry system is partially comprised of two tables, ORDERS_TAB (master table) and LINE_ITEMS_TAB (detail
2-24
Managing Sequences
table), that hold information about customer orders. A sequence named ORDER_SEQ is dened by the following statement:
CREATE SEQUENCE Order_seq START WITH 1 INCREMENT BY 1 NOMAXVALUE NOCYCLE CACHE 20;
Referencing a Sequence
A sequence is referenced in SQL statements with the NEXTVAL and CURRVAL pseudocolumns; each new sequence number is generated by a reference to the sequences pseudocolumn NEXTVAL, while the current sequence number can be repeatedly referenced using the pseudo-column CURRVAL. NEXTVAL and CURRVAL are not reserved words or keywords and can be used as pseudo-column names in SQL statements such as SELECTs, INSERTs, or UPDATEs. Generating Sequence Numbers with NEXTVAL To generate and use a sequence number, reference seq_name.NEXTVAL. For example, assume a customer places an order. The sequence number can be referenced in a values list. For example:
INSERT INTO Orders_tab (Orderno, Custno) VALUES (Order_seq.NEXTVAL, 1032);
Or, the sequence number can be referenced in the SET clause of an UPDATE statement. For example:
UPDATE Orders_tab SET Orderno = Order_seq.NEXTVAL WHERE Orderno = 10112;
The sequence number can also be referenced outermost SELECT of a query or subquery. For example:
SELECT Order_seq.NEXTVAL FROM dual;
As dened, the rst reference to ORDER_SEQ.NEXTVAL returns the value 1. Each subsequent statement that references ORDER_SEQ.NEXTVAL generates the next sequence number (2, 3, 4,. . .). The pseudo-column NEXTVAL can be used to generate as many new sequence numbers as necessary. However, only a single sequence number can be generated for each row. In other words, if NEXTVAL is referenced
Managing Sequences
more than once in a single statement, then the rst reference generates the next number, and all subsequent references in the statement return the same number. Once a sequence number is generated, the sequence number is available only to the session that generated the number. Independent of transactions committing or rolling back, other users referencing ORDER_SEQ.NEXTVAL obtain unique values. If two users are accessing the same sequence concurrently, then the sequence numbers each user receives might have gaps because sequence numbers are also being generated by the other user. Using Sequence Numbers with CURRVAL To use or refer to the current sequence value of your session, reference seq_name.CURRVAL. CURRVAL can only be used if seq_name.NEXTVAL has been referenced in the current user session (in the current or a previous transaction). CURRVAL can be referenced as many times as necessary, including multiple times within the same statement. The next sequence number is not generated until NEXTVAL is referenced. Continuing with the previous example, you would nish placing the customers order by inserting the line items for the order:
INSERT INTO Line_items_tab (Orderno, Partno, Quantity) VALUES (Order_seq.CURRVAL, 20321, 3); INSERT INTO Line_items_tab (Orderno, Partno, Quantity) VALUES (Order_seq.CURRVAL, 29374, 1);
Assuming the INSERT statement given in the previous section generated a new sequence number of 347, both rows inserted by the statements in this section insert rows with order numbers of 347. Uses and Restrictions of NEXTVAL and CURRVAL CURRVAL and NEXTVAL can be used in the following places:
s
VALUES clause of INSERT statements The SELECT list of a SELECT statement The SET clause of an UPDATE statement
A subquery A views query or snapshots query A SELECT statement with the DISTINCT operator A SELECT statement with a GROUP BY or ORDER BY clause
2-26
Managing Sequences
A SELECT statement that is combined with another SELECT statement with the UNION, INTERSECT, or MINUS set operator The WHERE clause of a SELECT statement DEFAULT value of a column in a CREATE TABLE or ALTER TABLE statement The condition of a CHECK constraint
Be sure the sequence cache can hold all the sequences used concurrently by your applications. Increase the number of values for each sequence held in the sequence cache.
The Number of Entries in the Sequence Cache When an application accesses a sequence in the sequence cache, the sequence numbers are read quickly. However, if an application accesses a sequence that is not in the cache, then the sequence must be read from disk to the cache before the sequence numbers are used. If your applications use many sequences concurrently, then your sequence cache might not be large enough to hold all the sequences. In this case, access to sequence numbers might often require disk reads. For fast access to all sequences, be sure your cache has enough entries to hold all the sequences used concurrently by your applications. The Number of Values in Each Sequence Cache Entry When a sequence is read into the sequence cache, sequence values are generated and stored in a cache entry. These values can then be accessed quickly. The number of sequence values stored in the cache is determined by the CACHE parameter in the CREATE SEQUENCE statement. The default value for this parameter is 20. This CREATE SEQUENCE statement creates the SEQ2 sequence so that 50 values of the sequence are stored in the SEQUENCE cache:
CREATE SEQUENCE Seq2 CACHE 50;
Managing Synonyms
The rst 50 values of SEQ2 can then be read from the cache. When the 51st value is accessed, the next 50 values will be read from disk. Choosing a high value for CACHE lets you access more successive sequence numbers with fewer reads from disk to the sequence cache. However, if there is an instance failure, then all sequence values in the cache are lost. Cached sequence numbers also could be skipped after an export and import if transactions continue to access the sequence numbers while the export is running. If you use the NOCACHE option in the CREATE SEQUENCE statement, then the values of the sequence are not stored in the sequence cache. In this case, every access to the sequence requires a disk read. Such disk reads slow access to the sequence. This CREATE SEQUENCE statement creates the SEQ3 sequence so that its values are never stored in the cache:
CREATE SEQUENCE Seq3 NOCACHE;
Dropping Sequences
To drop a sequence, use the SQL command DROP SEQUENCE. For example, the following statement drops the ORDER_SEQ sequence:
DROP SEQUENCE Order_seq;
When you drop a sequence, its denition is removed from the data dictionary. Any synonyms for the sequence remain, but return an error when referenced.
Managing Synonyms
A synonym is an alias for a table, view, snapshot, sequence, procedure, function, package, or object type. Synonyms let you refer to objects from other schemas
2-28
Managing Synonyms
without including the schema qualier. The following sections explain how to create, use, and drop synonyms using SQL commands.
Creating Synonyms
Use the SQL command CREATE SYNONYM to create a synonym. The following statement creates a public synonym named PUBLIC_EMP on the EMP_TAB table contained in the schema of JWARD:
CREATE PUBLIC SYNONYM Public_emp FOR jward.Emp_tab;
If the synonym named FIRE_EMP refers to a standalone procedure or package procedure, then you could execute it in SQL*Plus or Enterprise Manager with the command
EXECUTE Fire_emp(7344);
You can also use synonyms for GRANT and REVOKE statements, but not with other DML statements.
granted. For example, if you have the SELECT privilege for the JWARD.EMP_TAB synonym, then you can query the JWARD.EMP_TAB synonym, but you cannot insert rows using the synonym for JWARD.EMP_TAB.
Dropping Synonyms
To drop a synonym, use the SQL command DROP SYNONYM. To drop a private synonym, omit the PUBLIC keyword; to drop a public synonym, include the PUBLIC keyword. The following statement drops the private synonym named EMP_TAB:
DROP SYNONYM Emp_tab;
When you drop a synonym, its denition is removed from the data dictionary. All objects that reference a dropped synonym remain (for example, views and procedures) but become invalid.
2-30
SELECT Empno, Ename, Sal, Comm FROM Emp_tab WHERE Deptno = 30 WITH CHECK OPTION CONSTRAINT Sales_staff_cnst CREATE TABLE Dept_tab ( Deptno NUMBER(3) PRIMARY KEY, Dname VARCHAR2(15), Loc VARCHAR2(25)) CREATE TABLE Emp_tab ( Empno NUMBER(5) PRIMARY KEY, Ename VARCHAR2(15) NOT NULL, Job VARCHAR2(10), Mgr NUMBER(5), Hiredate DATE DEFAULT (sysdate), Sal NUMBER(7,2), Comm NUMBER(7,2), Deptno NUMBER(3) NOT NULL CONSTRAINT Dept_fkey REFERENCES Dept_tab(Deptno)) GRANT SELECT ON Sales_staff TO human_resources;
The CREATE SCHEMA command does not support Oracle extensions to the ANSI CREATE TABLE and CREATE VIEW commands (for example, the STORAGE clause).
database names. You should coordinate with your database administrator on this task, because it is usually the DBA who is responsible for assigning database names.
A session is established when a user logs onto a database. Object names are resolved relative to the current user session. The username of the current user is the default schema. The database to which the user has directly logged-on is the default database. Oracle has separate namespaces for different classes of objects. All objects in the same namespace must have distinct names, but two objects in different namespaces can have the same name. Tables, views, snapshots, sequences, synonyms, procedures, functions, and packages are in a single namespace. Triggers, indexes, and clusters each have their own individual namespace. For example, there can be a table, trigger, and index all named SCOTT.EMP_TAB. Based on the context of an object name, Oracle searches the appropriate namespace when resolving the name to an object. For example, in the following statement:
DROP CLUSTER Test
Oracle looks up TEST in the cluster namespace. Rather than supplying an object name directly, you can also refer to an object using a synonym. A private synonym name has the same syntax as an ordinary object name. A public synonym is implicitly in the PUBLIC schema, but users cannot explicitly qualify a synonym with the schema PUBLIC. Synonyms can only be used to reference objects in the same namespace as tables. Due to the possibility of synonyms, the following rules are used to resolve a name in a context that requires an object in the table namespace:
1.
2-32
2. 3. 4. 5.
If the name resolves to an object that is not a synonym, then no further work is necessary. If the name resolves to a private synonym, then replace the name with the denition of the synonym and return to step 1. If the name was originally qualied with a schema, then return an error; otherwise, check if the name is a public synonym. If the name is not a public synonym, return an error; otherwise, then replace the name with the denition of the public synonym and return to step 1.
When global object names are used in a distributed database (either explicitly or indirectly within a synonym), the local Oracle session resolves the reference as is locally required (for example, resolving a synonym to a remote tables global object name). After the partially resolved statement is shipped to the remote database, the remote Oracle session completes the resolution of the object as above.
See Also: See Oracle9i Database Concepts for more information
grants for the object are lost when the object is dropped. Privileges must be granted again when the object is re-created. If you use the RENAME command to rename a table, view, sequence, or a private synonym of a table, view, or sequence, then grants made for the object are carried forward for the new name, and the next statement renames the SALES_STAFF view:
RENAME Sales_staff TO Dept_30;
You cannot rename a stored PL/SQL program unit, public synonym, index, or cluster. To rename such an object, you must drop and re-create it. Renaming a schema object has the following effects:
All views and PL/SQL program units dependent on a renamed object become invalid (must be recompiled before next use). All synonyms for a renamed object return an error when used.
Subsequent SQL statements use this schema name for the schema qualier when the qualier is missing. Note that the session still has only the privileges of the current user and does not acquire any extra privileges by the above ALTER SESSION statement. For example:
CONNECT scott/tiger ALTER SESSION SET CURRENT_SCHEMA = joe; SELECT * FROM emp_tab;
Since emp_tab is not schema-qualied, the table name is resolved under schema joe. But if scott does not have select privilege on table joe.emp_tab, then scott cannot execute the SELECT statement.
ALL_OBJECTS, USER_OBJECTS ALL_CATALOG, USER_CATALOG ALL_TABLES, USER_TABLES ALL_TAB_COLUMNS, USER_TAB_COLUMNS ALL_TAB_COMMENTS, USER_TAB_COMMENTS
2-34
ALL_COL_COMMENTS, USER_COL_COMMENTS ALL VIEWS, USER_VIEWS ALL MVIEWS, USER_MVIEWS ALL_INDEXES, USER_INDEXES ALL_IND_COLUMNS, USER_IND_COLUMNS USER_CLUSTERS USER_CLU_COLUMNS ALL_SEQUENCES, USER_SEQUENCES ALL_SYNONYMS, USER_SYNONYMS ALL_DEPENDENCIES, USER_DEPENDENCIES
Example 1: Listing Different Schema Objects by Type The following query lists all of the objects owned by the user issuing the query:
SELECT Object_name, Object_type FROM User_objects;
Example 2: Listing Column Information Column information, such as name, datatype, length, precision, scale, and default data values, can be listed using one of the views ending with the _COLUMNS sufx. For example, the following query lists all of the default column values for the EMP_TAB and DEPT_TAB tables:
SELECT Table_name, Column_name, Data_default FROM User_tab_columns WHERE Table_name = DEPT_TAB OR Table_name = EMP_TAB;
Considering the example statements at the beginning of this section, a display similar to the one below is displayed:
TABLE_NAME ---------DEPT_TAB DEPT_TAB DEPT_TAB EMP_TAB EMP_TAB EMP_TAB EMP_TAB EMP_TAB EMP_TAB EMP_TAB EMP_TAB
COLUMN_NAME --------------DEPTNO DNAME LOC EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
DATA_DEFAULT --------------------
(NEW YORK)
(sysdate)
columns assume NULL when rows that do not specify values for these columns are inserted.
2-36
Example 3: Listing Dependencies of Views and Synonyms When you create a view or a synonym, the view or synonym is based on its underlying base object. The _DEPENDENCIES data dictionary views can be used to reveal the dependencies for a view and the _SYNONYMS data dictionary views can be used to list the base object of a synonym. For example, the following query lists the base objects for the synonyms created by the user JWARD:
SELECT Table_owner, Table_name FROM All_synonyms WHERE Owner = JWARD;
2-38
3
Selecting a Datatype
This chapter discusses how to use Oracle built-in datatypes in applications. Topics include:
s
Summary of Oracle Built-In Datatypes Representing Character Data Representing Numeric Data Representing Date and Time Data Representing Geographic Coordinate Data Representing Image, Audio, and Video Data Representing Searchable Text Data Representing Large Data Types Addressing Rows Directly with the ROWID Datatype ANSI/ISO, DB2, and SQL/DS Datatypes How Oracle Converts Datatypes Representing Dynamically Typed Data Representing XML Data
See Also:
s
Oracle9i Application Developers Guide - Object-Relational Features , for information about more complex types, such as object types, varrays, and nested tables. Oracle9i Application Developers Guide - Large Objects (LOBs) , for information about LOB datatypes. PL/SQL Users Guide and Reference , for information the PL/SQL data types. Many SQL datatypes are the same or similar in PL/SQL.
Character datatypes CHAR NCHAR VARCHAR2 and VARCHAR NVARCHAR2 CLOB NCLOB LONG
NUMBER datatype Time and date datatypes: DATE INTERVAL DAY TO SECOND INTERVAL YEAR TO MONTH TIMESTAMP
3-2
Another datatype, ROWID, is used for values in the ROWID pseudocolumn, which represents the unique address of each row in a table.
See Also: See Oracle9i SQL Reference for general descriptions of
these datatypes, and see Oracle9i Application Developers Guide Large Objects (LOBs) for information about the LOB datatypes. Table 31 summarizes the information about each Oracle built-in datatype.
Table 31 Summary of Oracle Built-In Datatypes
Datatype CHAR (size [BYTE | CHAR]) Description Fixed-length character data of length size bytes or characters. Column Length and Default Fixed for every row in the table (with trailing blanks); maximum size is 2000 bytes per row, default size is 1 byte per row. Consider the character set (single-byte or multibyte) before setting size. Variable for each row, up to 4000 bytes per row. Consider the character set (single-byte or multibyte) before setting size. A maximum size must be specied. Fixed for every row in the table (with trailing blanks). Column size is the number of characters. (The number of bytes is 2 times this number for the AL16UTF16 encoding and 3 times this number for the UTF8 encoding.) The upper limit is 2000 bytes per row. Default is 1 character.
NCHAR (size)
NVARCHAR2 (size) Variable-length Unicode character data of length size characters. A maximum size must be specied.
Single-byte character data Unicode national character set (NCHAR) data. Variable-length character data.
NUMBER (p, s)
Variable-length numeric data. Maximum precision p and/or scale s is 38. Fixed-length date and time data, ranging from Jan. 1, 4712 B.C.E. to Dec. 31, 4712 C.E.
DATE
A period of time, represented Fixed at 5 bytes. as years and months. The precision value species the number of digits in the YEAR eld of the date. The precision can be from 0 to 9, and defaults to 2 for years. A period of time, represented Fixed at 11 bytes. as days, hours, minutes, and seconds. The precision values specify the number of digits in the DAY and the fractional SECOND elds of the date. The precision can be from 0 to 9, and defaults to 2 for days and 6 for seconds.
3-4
Varies from 7 to 11 bytes, depending on the precision. The default is determined by the NLS_TIMESTAMP_FORMAT initialization parameter.
Up to 232 - 1 bytes, or 4 gigabytes. Up to 232 - 1 bytes, or 4 gigabytes. Variable for each row in the table, up to 2000 bytes per row. A maximum size must be specied. Provided for backward compatibility. Variable for each row in the table, up to 231 - 1 bytes, or 2 gigabytes, per row. Provided for backward compatibility.
LONG RAW
ROWID
Binary data representing row Fixed at 10 bytes (extended addresses ROWID) or 6 bytes (restricted ROWID) for each row in the table.
NCHAR (size)
NVARCHAR2 (size) Variable-length Unicode character data of length size characters. A maximum size must be specied.
Single-byte character data Unicode national character set (NCHAR) data. Variable-length character data.
NUMBER (p, s)
3-6
A period of time, represented Fixed at 5 bytes. as years and months. The precision value species the number of digits in the YEAR eld of the date. The precision can be from 0 to 9, and defaults to 2 for years. A period of time, represented Fixed at 11 bytes. as days, hours, minutes, and seconds. The precision values specify the number of digits in the DAY and the fractional SECOND elds of the date. The precision can be from 0 to 9, and defaults to 2 for days and 6 for seconds. A value representing a date and time, including fractional seconds. (The exact resolution depends on the operating system clock.) The precision value species the number of digits in the fractional second part of the SECOND date eld. The precision can be from 0 to 9, and defaults to 6 Varies from 7 to 11 bytes, depending on the precision. The default is determined by the NLS_TIMESTAMP_FORMAT initialization parameter.
TIMESTAMP (precision)
A value representing a date and time, plus an associated time zone setting. The time zone can be an offset from UTC, such as -5:0, or a region name, such as US/Pacific.
Up to 232 - 1 bytes, or 4 gigabytes. Up to 232 - 1 bytes, or 4 gigabytes. Variable for each row in the table, up to 2000 bytes per row. A maximum size must be specied. Provided for backward compatibility. Variable for each row in the table, up to 231 - 1 bytes, or 2 gigabytes, per row. Provided for backward compatibility.
LONG RAW
ROWID
Binary data representing row Fixed at 10 bytes (extended addresses ROWID) or 6 bytes (restricted ROWID) for each row in the table. Fixed-length character data of length size bytes or characters. Fixed for every row in the table (with trailing blanks); maximum size is 2000 bytes per row, default size is 1 byte per row. Consider the character set (single-byte or multibyte) before setting size. Variable for each row, up to 4000 bytes per row. Consider the character set (single-byte or multibyte) before setting size. A maximum size must be specied.
3-8
NVARCHAR2 (size) Variable-length Unicode character data of length size characters. A maximum size must be specied.
Single-byte character data Unicode national character set (NCHAR) data. Variable-length character data.
NUMBER (p, s)
Variable-length numeric data. Maximum precision p and/or scale s is 38. Fixed-length date and time data, ranging from Jan. 1, 4712 B.C.E. to Dec. 31, 4712 C.E.
DATE
A period of time, represented Fixed at 5 bytes. as years and months. The precision value species the number of digits in the YEAR eld of the date. The precision can be from 0 to 9, and defaults to 2 for years.
A period of time, represented Fixed at 11 bytes. as days, hours, minutes, and seconds. The precision values specify the number of digits in the DAY and the fractional SECOND elds of the date. The precision can be from 0 to 9, and defaults to 2 for days and 6 for seconds. A value representing a date and time, including fractional seconds. (The exact resolution depends on the operating system clock.) The precision value species the number of digits in the fractional second part of the SECOND date eld. The precision can be from 0 to 9, and defaults to 6 Varies from 7 to 11 bytes, depending on the precision. The default is determined by the NLS_TIMESTAMP_FORMAT initialization parameter.
TIMESTAMP (precision)
CHAR and NCHAR datatypes store xed-length character strings. VARCHAR2 and NVARCHAR2 datatypes store variable-length character strings. (The VARCHAR datatype is synonymous with the VARCHAR2 datatype.) NCHAR and NVARCHAR2 datatypes store Unicode character data only. CLOB and NCLOB datatypes store single-byte and multibyte character strings of up to four gigabytes.
See Also: Oracle9i Application Developers Guide - Large Objects
(LOBs)
s
The LONG datatype stores variable-length character strings containing up to two gigabytes, but with many restrictions.
3-10
This datatype is provided for backward compatibility with existing applications; in general, new applications should use CLOB and NCLOB datatypes to store large amounts of character data, and BLOB and BFILE to store large amounts of binary data. When deciding which datatype to use for a column that will store alphanumeric data in a table, consider the following points of distinction:
Space Usage
s
To store data more efciently, use the VARCHAR2 datatype. The CHAR datatype blank-pads and stores trailing blanks up to a xed column length for all column values, while the VARCHAR2 datatype does not add any extra blanks.
Comparison Semantics
s
Use the CHAR datatype when you require ANSI compatibility in comparison semantics (when trailing blanks are not important in string comparisons). Use the VARCHAR2 when trailing blanks are important in string comparisons.
Future Compatibility
s
The CHAR and VARCHAR2 datatypes are and will always be fully supported. At this time, the VARCHAR datatype automatically corresponds to the VARCHAR2 datatype and is reserved for future use.
CHAR, VARCHAR2, and LONG data is automatically converted from the database character set to the character set dened for the user session by the NLS_LANGUAGE parameter, where these are different.
allows -- multibyte characters. NAME VARCHAR2(32 CHAR); -- BIOGRAPHY can represent 2000 characters in any Unicode-representable language. -- The exact encoding depends on the national character set, but the column -- can contain multibyte values even if the database character set is single-byte. BIOGRAPHY NVARCHAR2(2000); -- The representation of COMMENT, as 2000 bytes or 2000 characters, depends -- on the initialization parameter NLS_LENGTH_SEMANTICS. COMMENT VARCHAR2(2000);
When using a multibyte database character encoding scheme, consider carefully the space required for tables with character columns. If the database character encoding scheme is single-byte, then the number of bytes and the number of characters in a column is the same. If it is multibyte, then there generally is no such correspondence. A character might consist of one or more bytes depending upon the specic multibyte encoding scheme, and whether shift-in/shift-out control codes are present. To avoid overowing buffers, specify data as NCHAR or NVARCHAR2 if it might use a Unicode encoding that is different from the database character set.
See Also:
s s s
Oracle9i Globalization and National Language Support Guide Oracle9i SQL Reference Oracle Time Series Users Guide
for information about globalization support within Oracle and support for different character encoding schemes.
3-12
Comparison Semantics
Oracle compares CHAR and NCHAR values using blank-padded comparison semantics. If two values have different lengths, then Oracle adds blanks at the end of the shorter value, until the two values are the same length. Oracle then compares the values character-by-character up to the rst character that differs. The value with the greater character in the rst differing position is considered greater. Two values that differ only in the number of trailing blanks are considered equal. Oracle compares VARCHAR2 and NVARCHAR2 values using non-padded comparison semantics. Two values are considered equal only if they have the same characters and are of equal length. Oracle compares the values character-by-character up to the rst character that differs. The value with the greater character in that position is considered greater. Because Oracle blank-pads values stored in CHAR columns but not in VARCHAR2 columns, a value stored in a VARCHAR2 column may take up less space than if it were stored in a CHAR column. For this reason, a full table scan on a large table containing VARCHAR2 columns may read fewer data blocks than a full table scan on a table containing the same data stored in CHAR columns. If your application often performs full table scans on large tables containing character data, then you might be able to improve performance by storing this data in VARCHAR2 columns rather than in CHAR columns. However, performance is not the only factor to consider when deciding which of these datatypes to use. Oracle uses different semantics to compare values of each datatype. You might choose one datatype over the other if your application is sensitive to the differences between these semantics. For example, if you want Oracle to ignore trailing blanks when comparing character values, then you must store these values in CHAR columns.
See Also: For more information on comparison semantics for
Or, you can specify a precision (total number of digits) and scale (number of digits to right of decimal point):
price NUMBER (8, 2)
Although not required, specifying precision and scale helps to identify bad input values. If a precision is not specied, the column stores values as given. The following table shows examples of how data different scale factors affect storage.
Specied As
NUMBER NUMBER (9) NUMBER (9,2) NUMBER (9,1) NUMBER (6) NUMBER (7, -2)
Stored As
7456123.89 7456124 7456123.89 7456123.9 (not accepted, exceeds precision) 7456100
See Also: For information about the internal format for the
3-14
Use TIMESTAMP WITH LOCAL TIME ZONE values when the time zone is not signicant. For example, you might use it in an application that schedules teleconferences, where each participant sees the start and end times for their own time zone. The TIMESTAMP WITH LOCAL TIME ZONE type is appropriate for two-tier applications where you want to display dates and times using the time zone of the client system. You should not use it in three-tier applications, such as those involving a web server, because in that case the client is the web server, so data displayed in a web browser is formatted according to the time zone of the web server rather than the time zone of the browser. Use INTERVAL DAY TO SECOND to represent the precise difference between two datetime values. For example, you might use this value to set a reminder for a time 36 hours in the future, or to record the time between the start and end of a race. To represent long spans of time, including multiple years, with high precision, you can use a large value for the days portion. Use INTERVAL YEAR TO MONTH to represent the difference between two datetime values, where the only signicant portions are the year and month. For example, you might use this value to set a reminder for a date 18 months in the future, or check whether 6 months have elapsed since a particular date. Oracle uses its own internal format to store dates. Date data is stored in xed-length elds of seven bytes each, corresponding to century, year, month, day, hour, minute, and second.
See Also: See the Oracle Call Interface Programmers Guide for a
Date Format
For input and output of dates, the standard Oracle default date format is DD-MON-RR. For example:
'13-NOV-1992'
To change this default date format on an instance-wide basis, use the NLS_DATE_FORMAT parameter. To change the format during a session, use the ALTER SESSION statement. To enter dates that are not in the current default date format, use the TO_DATE function with a format mask. For example:
TO_DATE ('November 13, 1992', 'MONTH DD, YYYY')
See Also: Oracle Julian dates might not be compatible with Julian
dates generated by other date algorithms. For information about Julian dates, see Oracle9i Database Concepts. Be careful using a date format like DD-MON-YY. The YY indicates the year in the current century. For example, 31-DEC-92 is December 31, 2092, not 1992 as you might expect. If you want to indicate years in any century other than the current one, use a different format mask, such as the default RR. Example: Printing a Date with BC/AD Notation
SQL> -- By default, the date is printed without any BC or AD qualifier. SQL> select sysdate from dual; SYSDATE --------24-JAN-02 SQL> -- Adding BC to the format string prints the date with BC or AD SQL> -- as appropriate. SQL> select to_char(sysdate, 'DD-MON-YYYY BC') from dual; TO_CHAR(SYSDAT -------------24-JAN-2002 AD
Time Format
Time is stored in 24-hour format, HH24:MI:SS. By default, the time in a DATE column is 12:00:00 A.M. (midnight) if no time portion is entered, or if the DATE is
3-16
truncated. In a time-only entry, the date portion defaults to the rst day of the current month. To enter the time portion of a date, use the TO_DATE function with a format mask indicating the time portion, as in:
Note: You may need to set up the following data structures for
INSERT INTO Birthdays_tab (bname, bday) VALUES ('ANNIE',TO_DATE('13-NOV-92 10:56 A.M.','DD-MON-YY HH:MI A.M.'));
ADD_MONTHS SYSDATE SYSTIMESTAMP TRUNC. When applied to a DATE value, it trims off the time portion so that it represents the very beginning of the day (the stroke of midnight). By truncating two DATE values and comparing them, you can check whether they refer to the same day. You can also use TRUNC along with a GROUP BY clause to produce daily totals. Arithmetic operators such as + and -. INTERVAL datatype. To represent constants when performing date arithmetic, you can use the INTERVAL datatype rather than performing your own calculations. For example, you might add or subtract INTERVAL constants from DATE values, or subtract two DATE values and compare the result to an INTERVAL. Comparison operators such as >, <, =, and BETWEEN.
EXTRACT NUMTODSINTERVAL NUMTOYMINTERVAL TO_DATE (and its opposite, TO_CHAR) TO_DSINTERVAL TO_TIMESTAMP TO_TIMESTAMP_TZ TO_YMINTERVAL
See Also:
function.
CURRENT_DATE CURRENT_TIMESTAMP DBTIMEZONE EXTRACT FROM_TZ LOCALTIMESTAMP SESSIONTIMEZONE SYS_EXTRACT_UTC SYSTIMESTAMP TO_TIMESTAMP_TZ
3-18
See Also:
function.
Process date information before, during, and after 1st January 2000 without error. This entails accepting date input, providing date output, storing date information and performing calculation on dates or portions of dates. Provide services as published in its documentation before, during and after 1st January 2000 without changes in operation resulting from the advent of the new century. Respond to two digit date input in a way that resolves ambiguity as to the century in a clearly dened manner. Manage the leap year occurring in the year 2000 according to the quad-centennial rule.
These criteria are a superset of the Year 2000 conformance requirements set out by the British Standards Institute in DISC PD-2000-1 A Denition of Year 2000 Conformity Requirements. You can warrant your application as Y2K compliant only if you have validated its conformance at all three of the following system levels:
s
Hardware System software, including databases, transaction processors and operating systems Application software, from third parties or developed in-house
If the current year is in the second half of the century (50 - 99), and a two-digit year between 00 and 49 is entered, this will be stored as a next century year. For example, 02 entered in 1996 will be stored as 2002. If the current year is in the second half of the century (50 - 99), and a two-digit year between 50 and 99 is entered, this will be stored as a current century year. For example, 97 entered in 1996 will be stored as 1997. If the current year is in the rst half of the century (00 - 49), and a two-digit year between 00 and 49 is entered, this will be stored as a current century year. For example, 02 entered in 2001 will be stored as 2002. If the current year is in the rst half of the century (00 - 49), and a two-digit year between 50 and 99 is entered, this will be stored as a previous century year. For example, 97 entered in 2001 will be stored as 1997.
3-20
The RR date format is available for inserting and updating DATE data in the database. It is not required for retrieval or query of data already stored in the database as Oracle has always stored the YEAR component of a date in its four-digit form. Here is an example of the RR usage:
INSERT INTO emp (empno, deptno,hiredate) VALUES (9999, 20, TO_DATE('01-jan-03', 'DD-MON-RR')); INSERT INTO emp (empno, deptno,hiredate) VALUES (8888, 20, TO_DATE('01-jan-67', 'DD-MON-RR')); SELECT empno, deptno, TO_CHAR(hiredate, 'DD-MON-YYYY') hiredate FROM emp;
The CC date format element of the TO_CHAR function sets the century value to one greater than the rst two digits of a four-digit year (for example, '20' from '1900'). For years that are a multiple of 100, this is not the true century. Strictly speaking, the century of '1900' is not the twentieth century (which began in 1901) but rather the nineteenth century.
The following workaround computes the correct century for any Common Era (CE, formerly known as AD) date. If userdate is a CE date for which you want the true century, use the following expression:
SELECT DECODE (TO_CHAR (Hiredate, 'YY'), '00', TO_CHAR (Hiredate - 366, 'CC'), TO_CHAR (Hiredate, 'CC')) FROM Emp_tab;
This expression works as follows: Get the last two digits of the year. If it is '00', then it is a year in which the Oracle century is one year too large, and compute a date in the preceding year (whose Oracle century is the desired true century). Otherwise, use the Oracle century.
See Also: For more information about date format codes, see
It is language-independent in that the months are numeric. It contains the full four-digit year so centuries are unambiguous. The time is represented fully. Since the most signicant elements occur rst, character-based sort operations will process the dates correctly.
3-22
V$NLS_DATABASE_PARAMETERS shows instance-wide Globalization Support parameters, whether the default or a value explicitly declared in the initialization parameter le. NLS_SESSION_PARAMETERS shows current session values, which may have been changed by ALTER SESSION.
A format model is a character that describes the format of DATE or NUMBER data stored in a character string. You may use the format model as an argument of the TO_CHAR or TO_DATE function for one of the following:
s
To specify the format for Oracle to use in returning a value from the database. To specify the format for a value you have specied for Oracle to store in the database.
Please note that the format does not change the internal representation of the value in the database. To see the available values for time zone region and time zone abbreviation, you can query the view V$TIMEZONE_NAMES.
Set the Client side, such as the Windows NT registry and Unix environment variables. Set theSession using ALTER SESSION SET NLS_DATE_FORMAT. To change the date format for the session, issue the following SQL command:
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-RR'
3.
Set the Server using the init.ora NLS_DATE_FORMAT parameter. To change the default date format for the entire database, change INIT.ORA to include the following
NLS_DATE_FORMAT = DD-MON-RR
The NLS_DATE_FORMAT setting relies on the above order. Therefore, for a client/server application, NLS_DATE_FORMAT must be set on the server and on the client.
Caution: Changing this parameter at the database level will change
all existing date elds as described above. Oracle Corporation suggests that you make changes at the session level unless all users and all currently running applications process dates in the range 1950-2049.
3-24
Y2K Example: Handling Feb. 29, 2000 The following unusual error helps illuminate the interaction between NLS_DATE_FORMAT and the Oracle RR format mask. The following is a syntactically correct statement but contains a logical aw:
SELECT TO_CHAR(TO_DATE(LAST_DAY(01-FEB-00),DD-MON-RR),MM/DD/RRRR) FROM DUAL;
The above query returns 02/28/2000. This is consistent with the dened behavior of the RR format element, but it is incorrect because the year 2000 is a leap year. The problem is that the operation is using the default NLS_DATE_FORMAT, which is 'DD-MON-YY'. If the NLS_DATE_FORMAT is changed to 'DD-MON-RR', then the same select returns 02/29/2000, which is the correct value. Let us evaluate the query as the Oracle Server engine does. The rst function processed is the innermost function, LAST_DAY. Because NLS_DATE_FORMAT is YY, this correctly returns 2/28, because it is using the year 1900 to evaluate the expression. The value 2/28 is then returned to the next outer function. So, the TO_DATE and TO_CHAR functions format the value 02/28/00 using the RR format mask and display the result as 02/28/2000. If SELECT LAST_DAY('01-FEB-00') FROM DUAL is issued, the result changes depending on the NLS_DATE_FORMAT. With YY, the LAST_DAY returned is 28-Feb-00 because the year is interpreted as 1900. With RR, the LAST_DAY returned is 29-Feb-00 because the year is interpreted as 2000. The year 1900 is not a leap year, but the year 2000 is. Y2K Example: Implicit Date Conversion within DECODE When the DECODE function is used and if the third argument has data type CHAR, VARCHAR2, or if it is NULL, then Oracle converts the return value to datatype VARCHAR2. Therefore, the following statement:
INSERT INTO destination_table (date_column) SELECT DECODE(31.12.2000, 00000000, NULL, TO_DATE(31.12.2000,DD.MM.YYYY)) FROM DUAL;
inserts date 04.10.1901. In the above examples, the third argument in the DECODE argument list is a NULL value, so Oracle implicitly converted the DATE value to a VARCHAR2 string using the default format mask. This is DD-MON-YY, hence loses the rst two digits of the year. Note: When inserting the record into a table, Oracle implicitly converts the string into a date, using the rst 2-digits of the current year. To ensure the correct year is interpreted, set NLS_DATE_FORMAT using RR or YYYY. Y2K Example: Partitioning Tables Based on DATE Columns If creating a partitioned table using a DATE data type column in the partition key, use a 4-digit year when specifying date ranges. For example:
CREATE TABLE stock_xactions (stock_symbol CHAR(5), stock_series CHAR(1), num_shares NUMBER(10), price NUMBER(5,2), trade_date DATE) STORAGE (INITIAL 100K NEXT 50K) LOGGING PARTITION BY RANGE (trade_date) (PARTITION sx1992 VALUES LESS THAN (TO_DATE(01-JAN-1993,DD-MON-YYYY)) TABLESPACE ts0 NOLOGGING, PARTITION sx1993 VALUES LESS THAN (TO_DATE(01-JAN-1994,DD-MON-YYYY)) TABLESPACE ts1, PARTITION sx1994 VALUES LESS THAN (TO_DATE(01-JAN-1995,DD-MON-YYYY)) TABLESPACE ts2);
Y2K Example: Views Dened Using 2-Digit Years Oracle views depend on the session state. In particular, a predicate with a 2-digit year, such as:
WHERE col > 12-MAY-99
is allowed in a view. Interpretation of the full 4-digit year depends on the setting of NLS_DATE_FORMAT.
3-26
Oracle9i Application Developers Guide - Large Objects (LOBs) for information about the CLOB and NCLOB datatypes. Oracle Call Interface Programmers Guide for details about each of the OCI functions. Oracle9i SQL Reference for syntax of the ALTER TABLE command.
This technique preserves all the constraints and triggers on the table. All indexes must be rebuilt. Any domain indexes on a long column, such as indexes for data cartridge or interMedia applications, must be dropped before changing the type of the column. Restrictions on Changing LONG or LONG RAW Columns to LOB Datatypes
1. 2. 3.
LOBs are not allowed in clustered tables. So if a table is a part of a cluster, its LONG or LONG RAW column cannot be changed to LOB. If a table is replicated or has materialized views, and its LONG column is changed to LOB, you might have to manually x the replicas. Not all triggers are preserved when the column is changed to a LOB datatype. LOB columns are not allowed in the column list of an UPDATE trigger. For example, the following trigger becomes invalid after changing the type of the column to a LOB, and cannot be recompiled:
3-28
CREATE TABLE t(changed_col LONG); CREATE TRIGGER trig BEFORE UPDATE OF lobcol ON t ...;
Transparent Access to LOBs from Applications that Use LONG and LONG RAW Datatypes
If your application uses DML (INSERT, UPDATE, DELETE) statements from SQL or PL/SQL for LONG or LONG RAW data, these statements work the same after the column is converted to a LOB datatype. You can use input parameters and output buffers of various character types, and they are converted to and from the corresponding LOB datatypes, and truncated if the output type is not large enough to hold the entire result. For example, you can SELECT a CLOB into a character variable, or a BLOB into a RAW variable. The following SQL functions that accept or output character types now accept or output CLOB data as well:
||, CONCAT, INSTR, INSTRB, LENGTH, LENGTHB, LIKE, LOWER, LPAD, LTRIM, NLS_LOWER, NLS_UPPER, NVL, REPLACE, RPAD, RTRIM, SUBSTR, SUBSTRB, TRIM, UPPER
In PL/SQL, all the SQLfunctions listed above and the comparison operators (>, =, < and !=), and all user-dened procedures and functions, accept CLOB datatypes as parameters or output types. You can also assign a CLOB to a character variable and vice versa in PL/SQL. If your application uses OCI calls to perform piecewise inserts, updates, or fetches of LONG data, these calls work the same after the column is converted to a LOB datatype. You can dene a CLOB column as SQLT_CHR or a BLOB column as SQLT_BIN and select the LOB data directly into a CHARACTER or RAW buffer without selecting out the locator rst. The OCI functions that provide this transparent access, by accepting datatypes of SQLT_LNG, SQLT_CHR, SQLT_BIN, and SQLT_LBI) are:
s
SELECT lists
A table can contain only one LONG column. You cannot create an object type with a LONG attribute. LONG columns cannot appear in WHERE clauses or in integrity constraints (except that they can appear in NULL and NOT NULL constraints). LONG columns cannot be indexed. A stored function cannot return a LONG value. You can declare a variable or argument of a PL/SQL program unit using the LONG datatype. However, you cannot then call the program unit from SQL. Within a single SQL statement, all LONG columns, updated tables, and locked tables must be located on the same database. LONG and LONG RAW columns cannot be used in distributed SQL statements and cannot be replicated. If a table has both LONG and LOB columns, you cannot bind more than 4000 bytes of data to both the LONG and LOB columns in the same SQL statement. However, you can bind more than 4000 bytes of data to either the LONG or the LOB column. A table with LONG columns cannot be stored in a tablespace with automatic segment-space management.
GROUP BY clauses, ORDER BY clauses, or CONNECT BY clauses or with the DISTINCT operator in SELECT statements The UNIQUE operator of a SELECT statement The column list of a CREATE CLUSTER statement The CLUSTER clause of a CREATE MATERIALIZED VIEW statement SQL built-in functions, expressions, or conditions SELECT lists of queries containing GROUP BY clauses SELECT lists of subqueries or queries combined by the UNION, INTERSECT, or MINUS set operators
3-30
SELECT lists of CREATE TABLE ... AS SELECT statements ALTER TABLE ... MOVE statements SELECT lists in subqueries in INSERT statements
A SQL statement within a trigger can insert data into a LONG column. If data from a LONG column can be converted to a constrained datatype (such as CHAR and VARCHAR2), a LONG column can be referenced in a SQL statement within a trigger. Variables in triggers cannot be declared using the LONG datatype. :NEW and :OLD cannot be used with LONG columns.
You can use the Oracle Call Interface functions to retrieve a portion of a LONG value from the database.
See Also: Oracle Call Interface Programmers Guide Note: If you design tables containing LONG or LONG RAW data, then you should place each LONG or LONG RAW column in its own table, along with a primary key value that lets you retrieve the LONG or LONG RAW columns through joins. This way, you can query the other columns without reading large amounts of irrelevant data.
Example of LONG Datatype To store information on magazine articles, including the texts of each article, create two tables. For example:
CREATE TABLE Article_header (Id NUMBER PRIMARY KEY, Title VARCHAR2(200), First_author VARCHAR2(30), Journal VARCHAR2(50), Pub_date DATE); CREATE TABLE article_text (Id NUMBER REFERENCES Article_header, Text LONG);
The ARTICLE_TEXT table stores only the text of each article. The ARTICLE_HEADER table stores all other information about the article, including the title, rst author, and journal and date of publication. The two tables are related by the referential integrity constraint on the ID column of each table. This design allows SQL statements to query data other than the text of an article without reading through the text. If you want to select all rst authors published in Nature magazine during July 1991, then you can issue this statement that queries the ARTICLE_HEADER table:
SELECT First_author FROM Article_header WHERE Journal = 'NATURE' AND TO_CHAR(Pub_date, 'MM YYYY') = '07 1991';
If the text of each article were stored in the same table with the rst author, publication, and publication date, then Oracle would need to read through the text to perform this query.
backward compatibility with existing applications. For new applications, you should use the BLOB and BFILE datatypes for large amounts of binary data.
(LOBs) for information about the BLOB and BFILE datatypes. The RAW and LONG RAW datatypes store data that is not interpreted by Oracle (that is, not converted when moving data between different systems). These datatypes are intended for binary data and byte strings. For example, LONG RAW can store graphics, sound, documents, and arrays of binary data; the interpretation is dependent on the use. Oracle Net and the Export and Import utilities do not perform character conversion when transmitting RAW or LONG RAW data. When Oracle automatically converts RAW or LONG RAW data to and from CHAR data (as is the case when entering RAW data as a literal in an INSERT statement), the data is represented as one hexadecimal
3-32
character representing the bit pattern for every four bits of RAW data. For example, one byte of RAW data with bits 11001011 is displayed and entered as 'CB'. LONG RAW data cannot be indexed, but RAW data can be indexed.
See Also: For more information about restrictions on LONG RAW
data, see "Restrictions on LONG and LONG RAW Datatypes" on page 3-29.
Data object (segment) identier Datale identier Block identier Row identier
The data object identier is an identication number that Oracle assigns to schema objects in the database, such as nonpartitioned tables or partitions. For example:
SELECT DATA_OBJECT_ID FROM ALL_OBJECTS WHERE OWNER = SCOTT AND OBJECT_NAME = EMP_TAB;
This query returns the data object identier for the EMP_TAB table in the SCOTT schema.
See Also: Oracle9i Supplied PL/SQL Packages and Types Reference for
information about other ways to get the data object identier, using the DBMS_ROWID package functions.
This command returns the ROWID pseudocolumn of the row of the EMP_TAB table that satises the query, and inserts it into the T1 table. Internal ROWID The internal ROWID is an internal structure that holds information that the server code needs to access a row. The restricted internal ROWID is 6 bytes on most platforms; the extended ROWID is 10 bytes on these platforms. External Character ROWID The extended ROWID pseudocolumn is returned to the client in the form of an 18-character string (for example, "AAAA8mAALAAAAQkAAA"), which represents a base 64 encoding of the components of the extended ROWID in a four-piece format, OOOOOOFFFBBBBBBRRR:
s
OOOOOO: The data object number identies the database segment (AAAA8m in the example). Schema objects in the same segment, such as a cluster of tables, have the same data object number. FFF: The datale that contains the row (le AAL in the example). File numbers are unique within a database. BBBBBB: The data block that contains the row (block AAAAQk in the example). Block numbers are relative to their datale, not tablespace. Therefore, two rows with identical block numbers could reside in two different datales of the same tablespace. RRR: The row in the block (row AAA in the example).
There is no need to decode the external ROWID; you can use the functions in the DBMS_ROWID package to obtain the individual components of the extended ROWID.
3-34
See Also: Oracle9i Supplied PL/SQL Packages and Types Reference for
information about the DBMS_ROWID package. The restricted ROWID pseudocolumn is returned to the client in the form of an 18-character string with a hexadecimal encoding of the datablock, row, and datale components of the ROWID. External Binary ROWID Some client applications use a binary form of the ROWID. For example, OCI and some precompiler applications can map the ROWID to a 3GL structure on bind or dene calls. The size of the binary ROWID is the same for extended and restricted ROWIDs. The information for the extended ROWID is included in an unused eld of the restricted ROWID structure. The format of the extended binary ROWID, expressed as a C struct, is:
struct riddef { ub4 ridobjnum; /* data obj#--this field is unused in restricted ROWIDs */ ub2 ridfilenum; ub1 filler; ub4 ridblocknum; ub2 ridslotnum; }
It is possible for an Oracle7 client to access a more recent database, and vice versa. A client in this sense can include a remote database accessing a server using database links, as well as a client 3GL or 4GL application accessing a server.
ROWID_TO_EXTENDED function in Oracle9i Supplied PL/SQL Packages and Types Reference and Oracle9i Database Migration. Accessing an Oracle7 Database from an Oracle9i Client The ROWID values that are returned are always restricted ROWIDs. Also, Oracle9i uses restricted ROWIDs when returning a ROWID value to an Oracle7 or earlier server. The following ROWID functionality works when accessing an Oracle7 Server:
s
Selecting a ROWID and using the obtained value in a WHERE clause WHERE CURRENT OF cursor operations Storing ROWIDs in user columns of ROWID or CHAR type Interpreting ROWIDs using the hexadecimal encoding (not recommended, use the DBMS_ROWID functions)
Accessing an Oracle9i Database from an Oracle7 Client Oracle9i returns ROWIDs in the extended format. This means that you can only:
s
Select a ROWID and use it in a WHERE clause Use WHERE CURRENT OF cursor operations Store ROWIDs in user columns of CHAR(18) datatype
Import and Export It is not possible for an Oracle7 client to import a table from a later version that has a ROWID column (not the ROWID pseudocolumn), if any row of the table contains an extended ROWID value.
3-36
ANSI SQL Datatype CHARACTER (n), CHAR (n) NUMERIC (p,s), DECIMAL (p,s), DEC (p,s) INTEGER, INT, SMALLINT FLOAT (p) REAL DOUBLE PRECISION CHARACTER VARYING(n), CHAR VARYING(n) TIMESTAMP TIMESTAMP WITH TIME ZONE
The IBM products SQL/DS, and DB2 datatypes TIME, GRAPHIC, VARGRAPHIC, and LONG VARGRAPHIC have no corresponding Oracle datatype and cannot be used. Table 34 shows the DB2 and SQL/DS conversions.
Table 34 SQL/DS, DB2 Datatype Conversions to Oracle Datatypes
DB2 or SQL/DS Datatype CHARACTER (n) VARCHAR (n) LONG VARCHAR DECIMAL (p,s) INTEGER, SMALLINT FLOAT (p) Oracle Datatype CHAR (n) VARCHAR2 (n) LONG NUMBER (p,s) NUMBER (38) FLOAT (p)
TO_NUMBER() TO_CHAR() TO_NCHAR() TO_DATE() HEXTORAW() RAWTOHEX() RAWTONHEX() ROWIDTOCHAR() ROWIDTONCHAR() CHARTOROWID() TO_CLOB() TO_NCLOB() TO_BLOB() TO_RAW()
3-38
NUMBER to VARCHAR2 or NVARCHAR2 VARCHAR2, NVARCHAR2, CHAR, or NCHAR to DATE DATE to VARCHAR2 or NVARCHAR2 VARCHAR2, NVARCHAR2, CHAR, or NCHAR to ROWID ROWID to VARCHAR2 or NVARCHAR2 VARCHAR2, NVARCHAR2, CHAR, NCHAR, or LONG to CLOB VARCHAR2, NVARCHAR2, CHAR, NCHAR, or LONG to NCLOB CLOB to CHAR, NCHAR, VARCHAR2, NVARCHAR2, and LONG NCLOB to CHAR, NCHAR, VARCHAR2, NVARCHAR2, and LONG NVARCHAR2, NCHAR, or BLOB to RAW RAW to BLOB VARCHAR2 or CHAR to HEX HEX to VARCHAR2
The assignment succeeds if Oracle can convert the datatype of the value used in the assignment to that of the assignments target. For the examples in the following list, assume a package with a public variable and a table declared as in the following statements:
Note: You may need to set up the following data structures for
variable := expression The datatype of expression must be either the same as, or convertible to, the datatype of variable. For example, Oracle automatically converts the data provided in the following assignment within the body of a stored procedure:
VAR1 := 0;
The datatypes of expression1, expression2, and so on, must be either the same as, or convertible to, the datatypes of the corresponding columns in table. For example, Oracle automatically converts the data provided in the following INSERT statement for TABLE1 (see table denition above):
INSERT INTO Table1_tab VALUES (19);
s
UPDATE table SET column = expression The datatype of expression must be either the same as, or convertible to, the datatype of column. For example, Oracle automatically converts the data provided in the following UPDATE statement issued against TABLE1:
UPDATE Table1_tab SET col1 = 30;
SELECT column INTO variable FROM table The datatype of column must be either the same as, or convertible to, the datatype of variable. For example, Oracle automatically converts data selected from the table before assigning it to the variable in the following statement:
SELECT Col1 INTO Var1 FROM Table1_tab WHERE Col1 = 30;
Character to NUMBER conversions succeed only if the character string represents a valid number. Character to DATE conversions succeed only if the character string satises the session default format, which is specied by the initialization parameter NLS_DATE_FORMAT. Some common types of expressions follow:
s
3-40
In general, Oracle uses the rule for expression evaluation when a datatype conversion is needed in places not covered by the rule for assignment conversions. In assignments of the form:
variable := expression
Oracle rst evaluates expression using the conversion rules for expressions; expression can be as simple or complex as desired. If it succeeds, then the evaluation of expression results in a single value and datatype. Then, Oracle tries to assign this value to the target variable using the conversion rules for assignments.
To manipulate and check type information, you can use the built-in type SYS.ANYTYPE in combination with the DBMS_TYPES package. For example, the following program represents data of different underlying types in a table, then interprets the underlying type of each row and processes each value appropriately:
-- The example below defines and executes a PL/SQL procedure that -- uses methods built into SYS.ANYDATA to access information about -- data stored in a SYS.ANYDATA table column. DROP TYPE Employee FORCE; DROP TABLE mytab; CREATE OR REPLACE TYPE Employee AS OBJECT ( empno NUMBER, ename VARCHAR2(10) ); / CREATE TABLE mytab ( id NUMBER, data SYS.ANYDATA ); INSERT INTO mytab VALUES (1, SYS.ANYDATA.ConvertNumber(5)); INSERT INTO mytab VALUES (2, SYS.ANYDATA.ConvertObject(Employee(5555, 'john'))); commit; CREATE OR REPLACE procedure P IS CURSOR cur IS SELECT id, data FROM mytab; v_id mytab.id%TYPE; v_data mytab.data%TYPE; v_type SYS.ANYTYPE; v_typecode PLS_INTEGER; v_typename VARCHAR2(60); v_dummy PLS_INTEGER; v_n NUMBER; v_employee Employee; non_null_anytype_for_NUMBER exception; unknown_typename exception; BEGIN OPEN cur; LOOP FETCH cur INTO v_id, v_data; EXIT WHEN cur%NOTFOUND; /* The typecode is a number that signifies what type is represented by v_data. GetType also produces a value of type SYS.AnyType with methods you can call to find precision and scale of a number, length of a string, and so on. */ v_typecode := v_data.GetType ( v_type /* OUT */ ); /* Now we compare the typecode against constants from DBMS_TYPES to see what kind of data we have, and decide how to display it. */
3-42
CASE v_typecode WHEN Dbms_Types.Typecode_NUMBER THEN IF v_type IS NOT NULL -- This condition should never happen, but we check just in case. THEN RAISE non_null_anytype_for_NUMBER; END IF; -- For each type, there is a Get method. v_dummy := v_data.GetNUMBER ( v_n /* OUT */ ); Dbms_Output.Put_Line ( To_Char(v_id) || ': NUMBER = ' || To_Char(v_n) ); WHEN Dbms_Types.Typecode_Object THEN v_typename := v_data.GetTypeName(); -- An object type's name is qualified with the schema name. IF v_typename NOT IN ( 'SCOTT.EMPLOYEE' ) -- If we encounter any object type besides EMPLOYEE, raise an exception. THEN RAISE unknown_typename; END IF; v_dummy := v_data.GetObject ( v_employee /* OUT */ ); Dbms_Output.Put_Line ( To_Char(v_id) || ': user-defined type = ' || v_typename || ' ( ' || v_employee.empno || ', ' || v_employee.ename || ' )' ); END CASE; END LOOP; CLOSE cur; EXCEPTION WHEN non_null_anytype_for_NUMBER THEN RAISE_Application_Error ( -20000, 'Paradox: the return AnyType instance FROM GetType ' || 'should be NULL for all but user-defined types' ); WHEN unknown_typename THEN RAISE_Application_Error ( -20000, 'Unknown user-defined type ' || v_typename || ' - program written to handle only SCOTT.EMPLOYEE' ); END; / -- The query and the procedure P in the preceding code sample -- produce output like the following: SQL> SELECT t.data.gettypename() FROM mytab t; T.DATA.GETTYPENAME() -------------------------------------------------------------------------------SYS.NUMBER SCOTT.EMPLOYEE SQL> EXEC P;
You can access the same features through the OCI interface, using the OCIType, OCIAnyData, and OCIAnyDataSet interfaces.
See Also:
Oracle9i Supplied PL/SQL Packages and Types Reference for details about the DBMS_TYPES package. Oracle9i Application Developers Guide - Object-Relational Features for information and examples using the ANYDATA, ANYDATASET, and ANYTYPE types. Oracle Call Interface Programmers Guide for details about the OCI interfaces.
3-44
See Also:
s
Oracle9i XML Developers Kits Guide - XDK for information about all aspects of working with XML. Oracle9i Supplied PL/SQL Packages and Types Reference for details about the XMLType type and the DBMS_XMLQuery, DBMS_XMLGEN, and DBMS_XMLSave packages. Oracle9i SQL Reference for information about the SYS_XMLGEN and SYS_XMLAGG functions.
3-46
4
Maintaining Data Integrity Through Constraints
This chapter explains how to enforce the business rules associated with your database and prevent the entry of invalid information into tables by using integrity constraints. Topics include the following:
s
Overview of Integrity Constraints Enforcing Referential Integrity with Constraints Managing Constraints That Have Associated Indexes Guidelines for Indexing Foreign Keys About Referential Integrity in a Distributed Database When to Use CHECK Integrity Constraints Examples of Dening Integrity Constraints Enabling and Disabling Integrity Constraints Altering Integrity Constraints Dropping Integrity Constraints Managing FOREIGN KEY Integrity Constraints Viewing Denitions of Integrity Constraints
Then, create a rule that every department listed in the employee table must match one of the values in the department table:
ALTER TABLE Emp_tab ADD FOREIGN KEY (Deptno) REFERENCES Dept_tab(Deptno);
When you add a new employee record to the table, Oracle automatically checks that its department number appears in the department table. To enforce this rule without integrity constraints, you can use a trigger to query the department table and test that each new employees department is valid. But this method is less reliable than the integrity constrain, because SELECT in Oracle uses "consistent read" and so the query might miss uncommitted changes from other transactions.
4-2
Constraints use existing indexes where possible, rather than creating new ones. Unique and primary keys can use non-unique as well as unique indexes. They can even use just the rst few columns of non-unique indexes. At most one unique or primary key can use each non-unique index. The column orders in the index and the constraint do not need to match. If you need to check whether an index is used by a constraint, for example when you want to drop the index, the object number of the index used by a unique or primary key constraint is stored in CDEF$.ENABLED for that constraint. It is not shown in any catalog view.
You should almost always index foreign keys, and the database does not do this for you.
values in the UNIQUE key; this combination of data integrity rules eliminates the possibility that any new rows data will ever attempt to conict with an existing rows data. Because Oracle indexes do not store keys that are all null, if you want to allow index-only scans of the table or some other operation that requires indexing all rows, put a NOT NULL constraint on at least one indexed column.
See Also: "Dening Relationships Between Parent and Child
Tables" on page 4-11 A NOT NULL constraint is specied like this: ALTER TABLE emp MODIFY ename NOT NULL;
Figure 41 Table with NOT NULL Integrity Constraints
Table EMP
EMPNO 7329 7499 7521 7566 ENAME SMITH ALLEN WARD JONES JOB CEO VPSALES MANAGER SALESMAN MGR 7329 7499 7521 HIREDATE 17DEC85 20FEB90 22FEB90 02APR90 SAL 9,000.00 7,500.00 5,000.00 2,975.00 COMM 100.00 200.00 400.00 DEPTNO 20 30 30 30
NOT NULL Constraint (no row may contain a null value for this column)
Absence of NOT NULL Constraint (any row can contain a null for this column)
4-4
Depending upon your business rules, you might use default values to represent zero or false, or leave the default values as NULL to signify an unknown value. Defaults are also useful when you use a view to make a subset of a tables columns visible. For example, you might allow users to insert rows through a view. The base table might also have a column named INSERTER, not included in the denition of the view, to log the user that inserts each row. To record the user name automatically, dene a default value that calls the USER function:
CREATE TABLE ( value1 value2 inserter ); audit_trail NUMBER, VARCHAR2(32), VARCHAR2(30) DEFAULT USER
Figure 42
UNIQUE Key Constraint (no row may duplicate a value in the constraint's column)
Table DEPT
DEPNO 20 30 40 DNAME LOC RESEARCH DALLAS SALES NEW MARKETING BOSTON
INSERT INTO 50 SALES NEW YORK This row violates the UNIQUE key constraint, because "SALES" is already present in another row; therefore, it is not allowed in the table. This row is allowed because a null value is entered for the DNAME column; however, if a NOT NULL constraint is also defined on the DNAME column, this row is not allowed.
60
BOSTON
Whenever practical, use a column containing a sequence number. It is a simple way to satisfy all the other guidelines. Minimize your use of composite primary keys. Although composite primary keys are allowed, they do not satisfy all of the other recommendations. For example, composite primary key values are long and cannot be assigned by sequence numbers. Choose a column whose data values are unique, because the purpose of a primary key is to uniquely identify each row of the table. Choose a column whose data values are never changed. A primary key value is only used to identify a row in the table, and its data should never be used for
4-6
any other purpose. Therefore, primary key values should rarely or never be changed.
s
Choose a column that does not contain any nulls. A PRIMARY KEY constraint, by denition, does not allow any row to contain a null in any column that is part of the primary key. Choose a column that is short and numeric. Short primary keys are easy to type. You can use sequence numbers to easily generate numeric primary keys.
An employees social security number (the primary key is the employee number) A trucks license plate number (the primary key is the truck number) A customers phone number, consisting of the two columns AREA and PHONE (the primary key is the customer number) A departments name and location (the primary key is the department number)
See Also: Oracle9i Data Warehousing Guide for information on query rewrite, materialized views, and the performance reasons for declaring constraints on views.
Figure 43 shows a foreign key dened on the department number. It guarantees that every value in this column must match a value in the primary key of the department table. This constraint prevents erroneous department numbers from getting into the employee table. Foreign keys can be comprised of multiple columns. Such a composite foreign key must reference a composite primary or unique key of the exact same structure, with the same number of columns and the same datatypes. Because composite primary and unique keys are limited to 32 columns, a composite foreign key is also limited to 32 columns.
By default (without any NOT NULL or CHECK clauses), the FOREIGN KEY constraint enforces the "match none" rule for composite foreign keys in the ANSI/ISO standard. To enforce the "match full" rule for nulls in composite foreign keys, which requires that all components of the key be null or all be non-null, dene a CHECK constraint that allows only all nulls or all non-nulls in the composite foreign key. For example, with a composite key comprised of columns A, B, and C:
4-8
CHECK ((A IS NULL AND B IS NULL AND C IS NULL) OR (A IS NOT NULL AND B IS NOT NULL AND C IS NOT NULL))
s
In general, it is not possible to use declarative referential integrity to enforce the "match partial" rule for nulls in composite foreign keys, which requires the non-null portions of the key to appear in the corresponding portions in the primary or unique key of a single row in the referenced table. You can often use triggers to handle this case, as described in Chapter 15, "Using Triggers".
Figure 43
Table DEPT
DEPTNO 20 30 40 DNAME RESEARCH SALES MARKETING LOC DALLAS NEW YORK BOSTON
Foreign Key (values in dependent table must match a value in unique key or primary key of referenced table)
Table EMP
EMPNO 7329 7499 7521 7566 ENAME SMITH ALLEN WARD JONES JOB CEO VPSALES MANAGER SALESMAN MGR 7329 7499 7521 HIREDATE 17DEC85 20FEB90 22FEB90 02APR90 SAL 9,000.00 7,500.00 5,000.00 2,975.00 COMM 100.00 200.00 400.00 DEPTNO 20 30 30 20
This row violates the referential constraint because "50" is not present in the referenced table's primary key; therefore, the row is not allowed in the table.
7571
FORD
MANAGER
7499
23FEB90
5,000.00
200.00
This row is allowed in the table because a null value is entered in the DEPTNO column; however, if a not null constraint is also defined for this column, this row is not allowed.
4-10
To enforce referential integrity rules between the EMP_TAB and INSURANCE tables (the FOREIGN KEY constraint) To guarantee that each employee has a unique membership number (the UNIQUE key constraint)
UNIQUE and NOT NULL Constraints on the Foreign Key When both UNIQUE and NOT NULL constraints are dened on the foreign key, only one row in the child table can reference a parent key value. Because nulls are not allowed in the foreign key, each row in the child table must explicitly reference a value in the parent key. This model establishes a "one-to-one" relationship between the parent and foreign keys that does not allow undetermined values (nulls) in the foreign key. If you expand the previous example by adding a NOT NULL constraint on the MEMBERNO column of the employee table, in addition to guaranteeing that each employee has a unique membership number, you also ensure that no undetermined values (nulls) are allowed in the MEMBERNO column of the employee table.
trigger.
The SET CONSTRAINTS setting lasts for the duration of the transaction, or until another SET CONSTRAINTS statement resets the mode.
See Also: For more details about the SET CONSTRAINTS statement, see the Oracle9i SQL Reference.
4-12
Tables that contain a large amount of data being manipulated by another application, which may or may not return the data in the same order Update cascade operations on foreign keys
When dealing with bulk data being manipulated by outside applications, you can defer checking constraints for validity until the end of a transaction. Ensure Constraints Are Created Deferrable After you have identied and selected the appropriate tables, make sure their FOREIGN, UNIQUE and PRIMARY key constraints are created deferrable. You can do so by issuing a statement similar to the following:
CREATE TABLE dept ( deptno NUMBER PRIMARY KEY, dname VARCHAR2 (30) ); CREATE TABLE emp ( empno NUMBER, ename VARCHAR2 (30), deptno NUMBER REFERENCES (dept), CONSTRAINT epk PRIMARY KEY (empno) DEFERRABLE, CONSTRAINT efk FOREIGN KEY (deptno) REFERENCES (dept.deptno) DEFERRABLE); INSERT INTO dept VALUES (10, Accounting); INSERT INTO dept VALUES (20, SALES); INSERT INTO emp VALUES (1, Corleone, 10); INSERT INTO emp VALUES (2, Costanza, 20); COMMIT; SET CONSTRAINT efk DEFERRED; UPDATE dept SET deptno = deptno + 10 WHERE deptno = 20; SELECT * from emp ORDER BY deptno; EMPNO ENAME DEPTNO ----- -------------- ------1 Corleone 10 2 Costanza 20 UPDATE emp SET deptno = deptno + 10 WHERE deptno = 20; SELECT * FROM emp ORDER BY deptno; EMPNO ----1 2 COMMIT; ENAME -------------Corleone Costanza DEPTNO ------10 30
Set All Constraints Deferred Within the application that manipulates the data, you must set all constraints deferred before you begin processing any data. Use the following DML statement to set all deferrable constraints deferred:
SET CONSTRAINTS ALL DEFERRED;
Note: The SET CONSTRAINTS statement applies only to the current transaction. The defaults specied when you create a constraint remain as long as the constraint exists. The ALTER SESSION SET CONSTRAINTS statement applies for the current session only.
Check the Commit (Optional) You can check for constraint violations before committing by issuing the SET CONSTRAINTS ALL IMMEDIATE statement just before issuing the COMMIT. If there are any problems with a constraint, this statement will fail and the constraint causing the error will be identied. If you commit while constraints are violated, the transaction will be rolled back and you will receive an error message.
Minimizing Space and Time Overhead for Indexes Associated with Constraints
When Oracle uses a unique index to enforce a constraint, and constraints associated with the unique index are dropped or disabled, the index is dropped. To preserve the statistics associated with the index, or if it would take a long time to re-create it, you can specify the KEEP INDEX clause on the DROP command for the constraint. While enabled foreign keys reference a PRIMARY or UNIQUE key, you cannot disable or drop the PRIMARY or UNIQUE key constraint or the index.
Note: Deferrable UNIQUE and PRIMARY keys all must use
non-unique indexes.
4-14
To reuse existing indexes when creating unique and primary key constraints, you can include USING INDEX in the constraint clause. Fpr example:
CREATE TABLE b ( b1 INTEGER, b2 INTEGER, CONSTRAINT unique1 (b1, b2) USING INDEX (CREATE UNIQUE INDEX b_index on b(b1, b2), CONSTRAINT unique2 (b1, b2) USING INDEX b_index );
If you decide to dene referential integrity across the nodes of a distributed database using triggers, be aware that network failures can make both the parent table and the child table inaccessible. For example, assume that the child table is in the SALES database, and the parent table is in the HQ database.
Note:
If the network connection between the two databases fails, then some DML statements against the child table (those that insert rows or update a foreign key value) cannot proceed, because the referential integrity triggers must have access to the parent table in the HQ database.
A CHECK constraint on employee salaries so that no salary value is greater than 10000. A CHECK constraint on department locations so that only the locations "BOSTON", "NEW YORK", and "DALLAS" are allowed. A CHECK constraint on the salary and commissions columns to prevent the commission from being larger than the salary.
The condition must be a boolean expression that can be evaluated using the values in the row being inserted or updated. The condition cannot contain subqueries or sequences.
4-16
The condition cannot include the SYSDATE, UID, USER, or USERENV SQL functions. The condition cannot contain the pseudocolumns LEVEL, PRIOR, or ROWNUM.
See Also: Oracle9i SQL Reference for an explanation of these
pseudocolumns.
s
At rst glance, this rule may be interpreted as "do not allow a row in the employee table unless the employees salary is greater than zero or the employees commission is greater than or equal to zero." But if a row is inserted with a null salary, that row does not violate the CHECK constraint regardless of whether the commission value is valid, because the entire check condition is evaluated as unknown. In this case, you can prevent such violations by placing NOT NULL integrity constraints on both the SAL and COMM columns.
Note: If you are not sure when unknown values result in NULL
conditions, review the truth tables for the logical operators AND and OR in Oracle9i SQL Reference
Therefore, NOT NULL integrity constraints for a single column can, in practice, be written in two forms: using the NOT NULL constraint or a CHECK constraint. For ease of use, you should always choose to dene NOT NULL integrity constraints, instead of CHECK constraints with the IS NOT NULL condition. In the case where a composite key can allow only all nulls or all values, you must use a CHECK integrity constraint. For example, the following expression of a CHECK integrity constraint allows a key value in the composite key made up of columns C1 and C2 to contain either all nulls or all values:
CHECK ((C1 IS NULL AND C2 IS NULL) OR (C1 IS NOT NULL AND C2 IS NOT NULL))
4-18
CHECK (loc IN (NEW YORK, BOSTON, CHICAGO))); CREATE TABLE Empno Ename Job Mgr Emp_tab ( NUMBER(5) CONSTRAINT Emp_pkey PRIMARY KEY, VARCHAR2(15) NOT NULL, VARCHAR2(10), NUMBER(5) CONSTRAINT Mgr_fkey REFERENCES Emp_tab, Hiredate DATE, Sal NUMBER(7,2), Comm NUMBER(5,2), Deptno NUMBER(3) NOT NULL CONSTRAINT dept_fkey REFERENCES Dept_tab ON DELETE CASCADE);
You cannot create a validated constraint on a table if the table already contains any rows that would violate the constraint.
4-20
When loading large amounts of data into a table using SQL*Loader When performing batch operations that make massive changes to a table (such as changing everyones employee number by adding 1000 to the existing number) When importing or exporting one table at a time
Enabling Constraints
When you dene an integrity constraint in a CREATE TABLE or ALTER TABLE statement, Oracle automatically enables the constraint by default. For code clarity, you can explicitly enable the constraint by including the ENABLE clause in its denition. Use this technique when creating tables that start off empty, and are populated a row at a time by individual transactions. In such cases, you want to ensure that data are consistent at all times, and the performance overhead of each DML operation is small. The following CREATE TABLE and ALTER TABLE statements both dene and enable integrity constraints:
CREATE TABLE Emp_tab ( Empno NUMBER(5) PRIMARY KEY); ALTER TABLE Emp_tab ADD PRIMARY KEY (Empno);
An ALTER TABLE statement that tries to enable an integrity constraint will fail if any rows of the table violate the integrity constraint. The statement is rolled back and the constraint denition is not stored and not enabled.
See Also: "Fixing Constraint Exceptions" on page 4-24 for more information about rows that violate integrity constraints.
Use this technique when creating tables that will be loaded with large amounts of data before anybody else accesses them, particularly if you need to cleanse data after loading it, or need to ll in empty columns with sequence numbers or parent/child relationships. An ALTER TABLE statement that denes and disables an integrity constraints never fails, because its rule is not enforced.
Enable a disabled constraint, using the ENABLE clause. Disable an enabled constraint, using the DISABLE clause.
4-22
An ALTER TABLE statement that attempts to enable an integrity constraint fails when the rows of the table violate the integrity constraint. The statement is rolled back and the constraint is not enabled.
See Also: "Fixing Constraint Exceptions" on page 4-24 for more information about rows that violate integrity constraints.
4-24
ENABLE VALIDATE; ALTER TABLE X1_tab MODIFY UNIQUE(A1) INITIALLY DEFERRED NORELY USING INDEX PCTFREE = 40 ENABLE NOVALIDATE; ALTER TABLE X1_tab MODIFY CONSTRAINT One_cnstrt INITIALLY IMMEDIATE RELY;
accept new_constraint set serveroutput on declare -- USER_CONSTRAINTS.CONSTRAINT_NAME is declared as VARCHAR2(30). -- Using %TYPE here protects us if the length changes in a future release. constraint_name user_constraints.constraint_name%type; begin select constraint_name into constraint_name from user_constraints where table_name = upper(&table_name.) and constraint_type = P; dbms_output.put_line(The primary key for || upper(&table_name.) || is: || constraint_name); execute immediate alter table &table_name. rename constraint || constraint_name || to &new_constraint.; end; /
When dropping UNIQUE, PRIMARY KEY, and FOREIGN KEY integrity constraints, you should be aware of several important issues and prerequisites. UNIQUE and PRIMARY KEY constraints are usually managed by the database administrator.
4-26
The Parent Table The creator of the referential integrity constraint must own the parent table or have REFERENCES object privileges on the columns that constitute the parent key of the parent table. The Child Table The creator of the referential integrity constraint must have the ability to create tables (that is, the CREATE TABLE or CREATE ANY TABLE system privilege) or the ability to alter the child table (that is, the ALTER object privilege for the child table or the ALTER ANY TABLE system privilege).
In both cases, necessary privileges cannot be obtained through a role; they must be explicitly granted to the creator of the constraint. These restrictions allow:
s
The owner of the child table to explicitly decide what constraints are enforced on her or his tables and the other users that can create constraints on her or his tables The owner of the parent table to explicitly decide if foreign keys can depend on the primary and unique keys in her tables
Prevent Update or Delete of Parent Key The default setting prevents the update or deletion of a parent key if there is a row in the child table that references the key. For example:
CREATE TABLE Emp_tab ( FOREIGN KEY (Deptno) REFERENCES Dept_tab);
Delete Child Rows When Parent Key Deleted The ON DELETE CASCADE action allows parent key data that is referenced from the child table to be deleted, but not updated. When data in the parent key is deleted, all rows in the child table that depend on the deleted parent key values are also deleted. To specify this referential action, include the ON DELETE CASCADE option in the denition of the FOREIGN KEY constraint. For example:
CREATE TABLE Emp_tab ( FOREIGN KEY (Deptno) REFERENCES Dept_tab ON DELETE CASCADE);
Set Foreign Keys to Null When Parent Key Deleted The ON DELETE SET NULL action allows data that references the parent key to be deleted, but not
4-28
updated. When referenced data in the parent key is deleted, all rows in the child table that depend on those parent key values have their foreign keys set to null. To specify this referential action, include the ON DELETE SET NULL option in the denition of the FOREIGN KEY constraint. For example:
CREATE TABLE Emp_tab ( FOREIGN KEY (Deptno) REFERENCES Dept_tab ON DELETE SET NULL);
You can query these views to nd the names of constraints, what columns they affect, and other information to help you manage constraints.
See Also: Refer to Oracle9i Database Reference for detailed
CHECK (Loc IN (NEW YORK, BOSTON, CHICAGO))); CREATE TABLE Emp_tab ( Empno NUMBER(5) PRIMARY KEY, Ename VARCHAR2(15) NOT NULL, Job VARCHAR2(10), Mgr NUMBER(5) CONSTRAINT Mgr_fkey REFERENCES Emp_tab ON DELETE CASCADE, Hiredate DATE, Sal NUMBER(7,2), Comm NUMBER(5,2), Deptno NUMBER(3) NOT NULL CONSTRAINT Dept_fkey REFERENCES Dept_tab);
Example 1: Listing All of Your Accessible Constraints The following query lists all constraints dened on all tables accessible to the user:
SELECT Constraint_name, Constraint_type, Table_name, R_constraint_name FROM User_constraints;
Considering the example statements at the beginning of this section, a list similar to the one below is returned:
CONSTRAINT_NAME --------------SYS_C00275 DNAME_UKEY LOC_CHECK1 SYS_C00278 SYS_C00279 SYS_C00280 MGR_FKEY DEPT_FKEY C P U C C C P R R TABLE_NAME ----------DEPT_TAB DEPT_TAB DEPT_TAB EMP_TAB EMP_TAB EMP_TAB EMP_TAB EMP_TAB R_CONSTRAINT_NAME ------------------
SYS_C00280 SYS_C00275
Some constraint names are user specied (such as DNAME_UKEY), while others are system specied (such as SYS_C00275). Each constraint type is denoted with a different character in the CONSTRAINT_TYPE column. The following table summarizes the characters used for each constraint type.
4-30
Constraint Type PRIMARY KEY UNIQUE KEY FOREIGN KEY CHECK, NOT NULL
Character P U R C
"V" in the CONSTRAINT_TYPE column. This constraint type corresponds to constraints created by the WITH CHECK OPTION for views. See Chapter 2, "Managing Schema Objects" for more information about views and the WITH CHECK OPTION. Example 2: Distinguishing NOT NULL Constraints from CHECK Constraints In the previous example, several constraints are listed with a constraint type of "C". To distinguish which constraints are NOT NULL constraints and which are CHECK constraints in the EMP_TAB and DEPT_TAB tables, issue the following query:
SELECT Constraint_name, Search_condition FROM User_constraints WHERE (Table_name = DEPT_TAB OR Table_name = EMP_TAB) AND Constraint_type = C;
Considering the example CREATE TABLE statements at the beginning of this section, a list similar to the one below is returned:
CONSTRAINT_NAME --------------LOC_CHECK1 SYS_C00278 SYS_C00279 SEARCH_CONDITION ---------------------------------------loc IN (NEW YORK, BOSTON, CHICAGO) ENAME IS NOT NULL DEPTNO IS NOT NULL
NOT NULL constraints are clearly identied in the SEARCH_CONDITION column. The conditions for user-dened CHECK constraints are explicitly listed in the SEARCH_CONDITION column.
Example 3: Listing Column Names that Constitute an Integrity Constraint The following query lists all columns that constitute the constraints dened on all tables accessible to you, the user:
SELECT Constraint_name, Table_name, Column_name FROM User_cons_columns;
Considering the example statements at the beginning of this section, a list similar to the one below is returned:
CONSTRAINT_NAME --------------DEPT_FKEY DNAME_UKEY DNAME_UKEY LOC_CHECK1 MGR_FKEY SYS_C00275 SYS_C00278 SYS_C00279 SYS_C00280 TABLE_NAME ----------EMP_TAB DEPT_TAB DEPT_TAB DEPT_TAB EMP_TAB DEPT_TAB EMP_TAB EMP_TAB EMP_TAB COLUMN_NAME --------------DEPTNO DNAME LOC LOC MGR DEPTNO ENAME DEPTNO EMPNO
4-32
5
Selecting an Index Strategy
This chapter discusses the considerations for using the different types of indexes in an application. The topics include:
s
Guidelines for Application-Specic Indexes Creating Indexes: Basic Examples When to Use Function-Based Indexes
See Also:
s
Oracle9i Database Performance Guide and Reference for detailed information about using indexes. Oracle9i Database Administrators Guide for information about creating and managing indexes. Oracle9i SQL Reference for the syntax of commands to work with indexes.
Create a new temporary tablespace using the CREATE TABLESPACE command. Use the TEMPORARY TABLESPACE option of the ALTER USER command to make this your new temporary tablespace. Create the index using the CREATE INDEX command. Drop this tablespace using the DROP TABLESPACE command. Then use the ALTER USER command to reset your temporary tablespace to your original temporary tablespace.
5-2
Under certain conditions, you can load data into a table with the SQL*Loader "direct path load", and an index can be created as data is loaded.
See Also: Oracle9i Database Utilities for information on direct path
load.
Create an index if you frequently want to retrieve less than 15% of the rows in a large table. The percentage varies greatly according to the relative speed of a table scan and how clustered the row data is about the index key. The faster the table scan, the lower the percentage; the more clustered the row data, the higher the percentage. Index columns used for joins to improve performance on joins of multiple tables. Primary and unique keys automatically have indexes, but you might want to create an index on a foreign key; see Chapter 4, "Maintaining Data Integrity Through Constraints" for more information. Small tables do not require indexes; if a query is taking too long, then the table might have grown from small to large.
Some columns are strong candidates for indexing. Columns with one or more of the following characteristics are candidates for indexing:
s
Values are relatively unique in the column. There is a wide range of values (good for regular indexes). There is a small range of values (good for bitmap indexes). The column contains many nulls, but queries often select all rows having a value. In this case, a comparison that matches all the non-null values, such as:
WHERE COL_X > -9.99 *power(10,125)
is preferable to
WHERE COL_X IS NOT NULL
This is because the rst uses an index on COL_X (assuming that COL_X is a numeric column). Columns with the following characteristics are less suitable for indexing:
There are many nulls in the column and you do not search on the non-null values.
LONG and LONG RAW columns cannot be indexed. The size of a single index entry cannot exceed roughly one-half (minus some overhead) of the available space in the data block. Consult with the database administrator for assistance in determining the space required by an index.
5-4
Table VENDOR_PARTS
VEND ID 1012 1012 1012 1010 1010 1220 1012 1292 PART NO 10440 10441 457 10440 457 08300 08300 457 UNIT COST .25 .39 4.95 .27 5.10 1.33 1.19 5.28
Assume that there are ve vendors, and each vendor has about 1000 parts. Suppose that the VENDOR_PARTS table is commonly queried by SQL statements such as the following:
SELECT * FROM vendor_parts WHERE part_no = 457 AND vendor_id = 1012;
To increase the performance of such queries, you might create a composite index putting the most selective column rst; that is, the column with the most values:
CREATE INDEX ind_vendor_id ON vendor_parts (part_no, vendor_id);
Composite indexes speed up queries that use the leading portion of the index. So in the above example, queries with WHERE clauses using only the PART_NO column also note a performance gain. Because there are only ve distinct values, placing a separate index on VENDOR_ID would serve no purpose.
It does not speed up queries. The table might be very small, or there might be many rows in the table but very few index entries. The queries in your applications do not use the index. The index must be dropped before being rebuilt.
When you drop an index, all extents of the indexs segment are returned to the containing tablespace and become available for other objects in the tablespace. Use the SQL command DROP INDEX to drop an index. For example, the following statement drops a specic named index:
DROP INDEX Emp_ename;
If you drop a table, then all associated indexes are dropped. To drop an index, the index must be contained in your schema or you must have the DROP ANY INDEX system privilege.
5-6
In this example, several storage settings are explicitly specied for the index:
CREATE INDEX emp_ename ON emp_tab(ename) TABLESPACE users STORAGE (INITIAL 20K NEXT 20k PCTINCREASE 75) PCTFREE 0 COMPUTE STATISTICS;
In this example, the index applies to two columns, to speed up queries that test either the rst column or both columns:
CREATE INDEX emp_ename ON emp_tab(ename, empno) COMPUTE STATISTICS;
In this example, the query is going to sort on the function UPPER(ENAME). An index on the ENAME column itself would not speed up this operation, and it might be slow to call the function for each result row. A function-based index precomputes the result of the function for each column value, speeding up queries that use the function for searching or sorting:
CREATE INDEX emp_upper_ename ON emp_tab(UPPER(ename)) COMPUTE STATISTICS;
You must set the QUERY_REWRITE_ENABLED initialization parameter to TRUE. The index is more effective if you gather statistics for the table or schema, using the procedures in the DBMS_STATS package. The index cannot contain any null values. Either make sure the appropriate columns contain no null values, or use the NVL function in the index expression to substitute some other value for nulls.
The expression indexed by a function-based index can be an arithmetic expression or an expression that contains a PL/SQL function, package function, C callout, or SQL function. Function-based indexes also support linguistic sorts based on collation keys, efcient linguistic collation of SQL statements, and case-insensitive sorts. Like other indexes, function-based indexes improve query performance. For example, if you need to access a computationally complex expression often, then you can store it in an index. Then when you need to access the expression, it is already computed. You can nd a detailed description of the advantages of function-based indexes in "Advantages of Function-Based Indexes" on page 5-9. Function-based indexes have all of the same properties as indexes on columns. However, unlike indexes on columns which can be used by both cost-based and
5-8
rule-based optimization, function-based indexes can be used by only by cost-based optimization. Other restrictions on function-based indexes are described in "Restrictions for Function-Based Indexes" on page 5-11.
See Also: For more information on function-based indexes, see
Oracle9i Database Concepts. For information on creating function-based indexes, see Oracle9i Database Administrators Guide.
Increase the number of situations where the optimizer can perform a range scan instead of a full table scan. For example, consider the expression in the WHERE clause below:
CREATE INDEX Idx ON Example_tab(Column_a + Column_b); SELECT * FROM Example_tab WHERE Column_a + Column_b < 10;
The optimizer can use a range scan for this query because the index is built on (column_a + column_b). Range scans typically produce fast response times if the predicate selects less than 15% of the rows of a large table. The optimizer can estimate how many rows are selected by expressions more accurately if the expressions are materialized in a function-based index. (Expressions of function-based indexes are represented as virtual columns and ANALYZE can build histograms on such columns.)
s
Precompute the value of a computationally intensive function and store it in the index. An index can store computationally intensive expression that you access often. When you need to access a value, it is already computed, greatly improving query execution performance. Create indexes on object columns and REF columns. Methods that describe objects can be used as functions on which to build indexes. For example, you can use the MAP method to build indexes on an object type column. Create more powerful sorts. You can perform case-insensitive sorts with the UPPER and LOWER functions, descending order sorts with the DESC keyword, and linguistic-based sorts with the NLSSORT function.
order. Such indexes are treated as function-based indexes. Descending indexes cannot be bitmapped or reverse, and cannot be used in bitmapped optimizations. To get the pre-Oracle 8.1 release DESC functionality, remove the DESC keyword from the CREATE INDEX statement. Another function-based index calls the object method distance_from_equator for each city in the table. The method is applied to the object column Reg_Obj. A query could use this index to quickly nd cities that are more than 1000 miles from the equator:
CREATE INDEX Distance_index ON Weatherdata_tab (Distance_from_equator (Reg_obj)); SELECT * FROM Weatherdata_tab WHERE (Distance_from_equator (Reg_Obj)) > 1000;
Another index stores the temperature delta and the maximum temperature. The result of the delta is sorted in descending order. A query could use this index to quickly nd table rows where the temperature delta is less than 20 and the maximum temperature is greater than 75.
CREATE INDEX compare_index ON Weatherdata_tab ((Maxtemp - Mintemp) DESC, Maxtemp); SELECT * FROM Weatherdata_tab WHERE ((Maxtemp - Mintemp) < 20 AND Maxtemp > 75);
The SELECT command uses the function-based index on UPPER(e_name) to return all of the employees with name like :KEYCOL.
SELECT * FROM Emp_tab WHERE UPPER(Ename) like :KEYCOL;
5-10
The SELECT statement can either use index range scan (since the expression is a prex of index IDX) or index fast full scan (which may be preferable if the index has specied a high parallel degree).
SELECT a FROM Fbi_tab WHERE A + B * (C - 1) < 100;
The SELECT statement selects all of the contents of the table and orders it by NAME. The rows are ordered using the German collation sequence. The Globalization Support parameters are not needed in the SELECT statement, because in a German session, NLS_SORT is set to German and NLS_COMP is set to ANSI.
SELECT * FROM Nls_tab WHERE Name IS NOT NULL ORDER BY Name;
Only cost-based optimization can use function-based indexes. Remember to set the QUERY_REWRITE_ENABLED initialization parameter to TRUE, and call DBMS_STATS.GATHER_TABLE_STATISTICS or DBMS_STATS.GATHER_SCHEMA_STATISTICS, for the function-based index to be effective. Any top-level or package-level PL/SQL functions that are used in the index expression must be declared as DETERMINISTIC. That is, they always return the same result given the same input, like the UPPER function. You must ensure that the subprogram really is deterministic, because Oracle does not check that the assertion is true.
The following semantic rules demonstrate how to use the keyword DETERMINISTIC:
s
A top level subprogram can be declared as DETERMINISTIC. A PACKAGE level subprogram can be declared as DETERMINISTIC in the PACKAGE specication but not in the PACKAGE BODY. Errors are raised if DETERMINISTIC is used inside a PACKAGE BODY. A private subprogram (declared inside another subprogram or a PACKAGE BODY) cannot be declared as DETERMINISTIC. A DETERMINISTIC subprogram can call another subprogram whether the called program is declared as DETERMINISTIC or not.
Expressions used in a function-based index cannot contain any aggregate functions. The expressions should reference only columns in a row in the table. You must have the initialization parameters COMPATIBLE set to 8.1.0.0.0 or higher, QUERY_REWRITE_ENABLED=TRUE, and QUERY_REWRITE_INTEGRITY=TRUSTED. You must analyze the table or index before the index is used. Bitmap optimizations cannot use descending indexes. Function-based indexes are not used when OR-expansion is done. The index function cannot be marked NOT NULL. To avoid a full table scan, you must ensure that the query cannot fetch null values. Function-based indexes cannot use expressions that return VARCHAR2 or RAW data types of unknown length from PL/SQL functions. A workaround is to limit the size of the functions output by indexing a substring of known length:
-- The INITIALS() function might return 1 letter, 2 letters, 3 letters, etc. -- We limit the return value to 10 characters for purposes of the index. CREATE INDEX func_substr_index ON emp_tab(substr(initials(ename),1,10); -- Call SUBSTR both when creating the index and when referencing -- the function in queries. SELECT SUBSTR(initials(ename),1,10) FROM emp_tab;
5-12
6
Speeding Up Index Access with Index-Organized Tables
This chapter covers the following topics:
s
What Are Index-Organized Tables? Features of Index-Organized Tables Why Use Index-Organized Tables? Example of an Index-Organized Table
See Also: For the syntax of the ORGANIZATION INDEX clause of
present at that location. The index-organized table eliminates the I/O operation of following a rowid back to table data.
6-2
Best table organization for 24x7 operations When your database must be
available 100% of the time, index-organized tables provide the following advantages:
s
You can reorganize an index-organized table or an index-organized table partition (to recover space or improve performance) without rebuilding its secondary indexes. This results in a short reorganization maintenance window. You can reorganize an index-organized table online.Along with online reorganization of secondary indexes, this capability eliminates the reorganization maintenance window.
Reduced storage requirements The key columns are not duplicated in both the table and the index, and no additional storage is needed for rowids. When the key columns take up a large part of the row, the storage savings can be as much as 50%.
Figure 61 Ordinary Table and an Index versus Index-Organized Table
Primary Key Index All data stored in index DBMS 1 DBMS 2 Oracle 1 Oracle 2 17 2 14 31
17 2 14 31
ordinary tables are available for index-organized tables. This includes ADD, MODIFY, and DROP COLUMNS and CONSTRAINTS. However, the primary key constraint for an index-organized table cannot be dropped, deferred, or disabled.
Logical ROWID Support Because of the inherent movability of rows in a B*-tree index, a secondary index on an index-organized table cannot be based on a physical rowid, which is inherently xed. Instead, a secondary index for an index-organized table is based on the logical rowid. An index-organized table row has no permanent physical address and can move across data blocks when new rows are inserted. However, even if the physical location of a row changes, its logical rowid remains valid.
A logical rowid includes the tables primary key and a physical guess which identies the database block address at which the row is likely to be found. The physical guess makes rowid-based access to non-volatile index-organized tables comparable to similar access of ordinary tables. Logical rowids are similar to physical rowids in the following ways:
s
You can select ROWID from an index-organized table, and access the rows using ROWID as a column name in a WHERE clause. Access through the logical rowid is the fastest possible way to get to a specic row, even if it takes more than one block access to get it. The same logical rowid can be used to access a row as long as the primary key value for the row does not change.
The database server uses a single datatype, called universal rowid, to support both logical and physical rowids. To switch to index-organized tables, applications that use rowids might have to change to universal rowids, but these changes are made easier by the UROWID datatype, which lets applications access logical and physical rowids in a unied manner.
For more information:
6-4
Secondary Index Support Secondary indexes on index-organized tables differ from indexes on ordinary tables in two ways:
s
They store logical rowids instead of physical rowids. Thus, a table maintenance operation such as ALTER TABLE MOVE does not make the secondary index unusable. The logical rowid also includes a physical guess that provides a direct access to the index leaf block containing the index-organized table row. If the physical guess is correct, a secondary index scan would incur a single additional I/O once the secondary key is found. The performance would be similar to that of a secondary index-scan on an ordinary table.
Both unique and non-unique secondary indexes, as well as function-based secondary indexes, are supported. Bitmap indexes on non-partitioned index-organized tables are supported, provided the index-organized table is created with a mapping table. For more information about mapping tables, see the information about index-organized tables in Oracle9i Database Concepts
LOB Columns You can create internal and external LOB columns in index-organized tables to store large unstructured data such as audio, video, and images. The SQL DDL, DML, and piece-wise operations on LOBs in index-organized tables exhibit the same behavior as in ordinary tables. The main differences are:
s
Tablespace mappingBy default (or unless specied otherwise), the LOBs data and index segments are created in the tablespace in which the primary key index segment of the index-organized table is created. Inline versus Out-of-line storageLOBs in index-organized tables with overow segments are the same as those in ordinary tables. All LOBs in index-organized tables created without an overow segment are stored out-of-line (that is, the default storage attribute is DISABLE STORAGE IN ROW). Specifying an ENABLE STORAGE IN ROW for such LOBs causes an error.
LOB columns are supported in range-partitioned index-organized tables. Other LOB featuressuch as BFILEs, temporary LOBs, and varying character width LOBsare also supported in index-organized tables. You use them as you would in ordinary tables.
Parallel Query Queries on index-organized tables involving primary key index
tables, including Object Type, VARRAYs, Nested Table, and REF Columns.
SQL*Loader This utility supports both ordinary and direct path load of
index-organized tables and their associated indexes (including partitioning support). However, direct path parallel load to an index-organized table is not supported. An alternate method of achieving the same result is to perform parallel load to an ordinary table using SQL*Loader, then use the parallel CREATE TABLE AS SELECT option to build the index-organized table.
Export/Import This utility supports export (both ordinary and direct path) and
The Oracle Enterprise Manager supports generating SQL statements for CREATE and ALTER operations on an index-organized table.
key column prexes in index-organized tables and indexes. The salient characteristics of the scheme are:
s
Key compression breaks an index key into a prex entry and sufx entry. Compression is achieved by sharing the prex entries among all the sufx entries in an index block. Only keys in the leaf blocks of a B*-tree are compressed. Keys in the branch blocks of a B*-tree are still sufx truncated but not subjected to key compression.
6-6
Queuing provides message queuing as an integrated part of the database server, and uses index-organized tables to hold metadata information for multiple consumer queues.
Index-Organized Tables Avoid Redundant Data Storage For tables, where the
majority of columns form the primary key, there is a signicant amount of redundant data stored. You can avoid this redundant storage by using an index-organized table. Also, by using an index-organized table, you increase the efciency of the primary key-based access to non-key columns.
Index-Organized Tables Are Suited to VLDB and OLTP Applications The ability to
partition index-organized tables on a range of column values makes them suitable for VLDB applications. One major advantage of an index-organized table comes from the logical nature of its secondary indexes. After an ALTER TABLE MOVE and SPLIT operation, global indexes on index-organized tables remain usable because the index rows contain logical rowids. You can avoid a complete index rebuild, which can be very expensive. Also, the ALTER TABLE MOVE operation can be done on-line, making index-organized tables ideal for applications requiring 24x7 availability. Similarly, after an ALTER TABLE MOVE operation, local indexes on index-organized tables are still usable. These partition maintenance operations do make the local and global indexes on index-organized table slower as the guess component of the logical rowid becomes invalid. However, the indexes are still usable through the primary key-component of the logical rowid. Note that the invalid physical guesses in these indexes can be xed online with the help of ALTER INDEX ... UPDATE BLOCK REFERENCES operation.
Index-Organized Tables Are Suited to Time-Series Applications Time-series applications use a set of time-stamped rows belonging to a single item, such as a stock price. The ability to cluster rows based on the primary key makes index-organized tables attractive for such applications. By dening an index-organized table with primary key (stock symbol, time stamp), the Oracle8 Time Series option can store and manipulate time-series data efciently. You can
achieve more storage savings by compressing repeated occurrences of the item identier (for example, the stock symbol) in a time series by using an index-organized table with key compression.
Index-Organized Tables Store Nested Tables Efciently For a nested table
column, Oracle internally creates a storage table to hold all the nested table rows. You can store the nested table as an index-organized table:
CREATE TYPE Project_t AS OBJECT(Pno NUMBER, Pname VARCHAR2(80)); CREATE TYPE Project_set AS TABLE OF Project_t; CREATE TABLE Employees (Eno NUMBER, Projects PROJECT_SET) NESTED TABLE Projects_ntab STORE AS Emp_project_tab ((PRIMARY KEY(Nested_table_id, Pno)) ORGANIZATION INDEX) RETURN AS LOCATOR;
The rows belonging to a single nested table instance are identied by a NESTED_TABLE_ID column. If an ordinary table is used to store nested table columns, the nested table rows typically get de-clustered. But when you use an index-organized table, the nested table rows can be clustered based on the NESTED_TABLE_ID column. The Extensible Indexing Framework lets you add a new access method to the database. Typically, domain-specic indexing schemes need some storage mechanism to hold their index data. Index-organized tables are ideal candidates for such domain index storage. The interMedia Spatial and Text features use index-organized tables for storing their index data.
Index-Organized Tables can Store Extensible Index Data
6-8
This example illustrates some of the basic tasks in creating and using index-organized tables. In this example, a text search engine keeps a record of all the web pages that use specic words or phrases, so that it can return a list of hypertext links in response to a search query. This example illustrates the following tasks:
s
Moving Existing Data from an Ordinary Table into an Index-Organized Table: Example Creating Index-Organized Tables: Example Declaring a Universal Rowid Datatype: Example Creating Secondary Indexes on Index-Organized Tables: Example
Manipulating Index-Organized Tables: Example Specifying an Overow Data Segment: Example Determining the Last Non-Key Column Included in the Index Row Head Piece: Example Storing Columns in the Overow Segment: Example Modifying Physical and Storage Attributes: Example Partitioning an Index-Organized Table: Example Rebuilding an Index-Organized Table: Example
Moving Existing Data from an Ordinary Table into an Index-Organized Table: Example
The CREATE TABLE AS SELECT command lets you move existing data from an ordinary table into an index-organized table. In the following example, an index-organized table, called docindex, is created from an ordinary table called doctable.
CREATE TABLE Docindex ( Token, Doc_id, Token_frequency, CONSTRAINT Pk_docindex PRIMARY KEY (Token, Doc_id) ) ORGANIZATION INDEX TABLESPACE Ind_tbs PARALLEL (DEGREE 2) AS SELECT * from Doc_tab;
Note that the PARALLEL clause allows the table creation to be performed in parallel.
6-10
This secondary index allows Oracle to efciently process queries involving predicates on doc_id, as the following example illustrates.
SELECT Token FROM Docindex WHERE Doc_id = 1;
Also, you can use SELECT FOR UPDATE statements to lock rows of an index-organized table. All of these operations result in manipulating the primary key B*-tree index. Both query and DML operations involving index-organized tables are optimized by using this cost-based approach.
Each additional non-key column stored in the primary key index reduces the dense clustering of index rows in the B*-tree index leaf blocks or because
A leaf block of aB*-tree must hold at least two index rows, and putting all non-key columns as part of an index row may not be possible.
To overcome these problems, you can associate an overow data segment with an index-organized table. In the following example, an additional column, token_offsets, is required for the docindex table. This example shows how you can create an index-organized table and use the OVERFLOW option to create an overow data segment.
CREATE TABLE Docindex2 ( Token CHAR(20), Doc_id NUMBER, Token_frequency NUMBER, Token_offsets VARCHAR(512), CONSTRAINT Pk_docindex2 PRIMARY KEY (Token, Doc_id) ) ORGANIZATION INDEX TABLESPACE Ind_tbs PCTTHRESHOLD 20 OVERFLOW TABLESPACE Ovf_tbs INITRANS 4;
For the overow data segment, you can specify physical storage attributes such as TABLESPACE, INITRANS, and so on. For an index-organized table with an overow segment, the index row contains a <key, row head> pair, where the row head contains the rst few non-key columns and a rowid that points to an overow row-piece containing the remaining column values. Although this approach incurs the storage cost of one rowid for each row, it nevertheless avoids key column duplication.
6-12
Non-key Cols
Determining the Last Non-Key Column Included in the Index Row Head Piece: Example
To determine the last non-key column to include in the index row head piece, you use the PCTTHRESHOLD option specied as a percentage of the leaf block size. The remaining non-key columns are stored in the overow data segment as one or more row-pieces. Specically, the last non-key column to be included is chosen so that the index row size (key +row head) does not exceed the specied threshold (which, in the following example, is 20% of the index leaf block). By default, PCTTHRESHOLD is set at 50 when omitted. The PCTTHRESHOLD option determines the last non-key column to be included in the index for each row. It does not, however, allow you to specify that the same set of columns be included in the index for all rows in the table. For this purpose, the INCLUDING option is provided. The CREATE TABLE statement in the following example includes all the columns up to the token_frequency column in the index leaf block and forces the token_offsets column to the overow segment.
CREATE TABLE Docindex3 ( Token CHAR(20), Doc_id NUMBER, Token_frequency NUMBER, Token_offsets VARCHAR(512), CONSTRAINT Pk_docindex3 PRIMARY KEY (Token, Doc_id)
Such vertical partitioning of a row between the index and data segments allows for higher clustering of rows in the index. This results in better query performance for the columns stored in the index. For example, if the token_offsets column is infrequently accessed, then pushing this column out of the index results in better clustering of index rows in the primary key B*-tree structure (Figure 63). This in turn results in overall improved query performance. However, there is one additional block access for columns stored in the overow data segment, and this can slow performance.
6-14
PCTTHRESHOLD option forces token_offsets into overflow segments for some rows
17 2 14 31 ...
INCLUDING option forces token_offsets into overflow segment for all rows
17 2 14 31 ...
For index-organized tables created without an overow data segment, you can add an overow data segment using ALTER TABLE ADD OVERFLOW option. The following example shows how to add an overow segment to the docindex table.
ALTER TABLE Docindex ADD OVERFLOW;
The ANALYZE command analyzes both the primary key index segment and the overow data segment, and computes logical as well as physical statistics for the table. You can determine how many rows have one or more chained overow row-pieces using the ANALYZE LIST CHAINED ROWS option. With the logical rowid feature, a separate CHAINED_ROWS table is not needed.
You must specify the ORGANIZATION INDEX clause to create an index-organized table as part of table-level attributes. This property is implicitly inherited by all partitions. You must specify the OVERFLOW option as part of table-level attribute to create an index-organized table with overow data segment. The OVERFLOW option results in the creation of overow data segments, which are themselves equi-partitioned with the primary key index segments. That is, each partition has an index segment and an overow data segment. For hash-partitioned tables, include the ROW MOVEMENT ENABLE clause of the CREATE TABLE statement. Rows might move from one partition to another due to changes in the columns used to derive the hash value.
6-16
As in ordinary partitioned tables, you can specify default values for physical attributes at the table-level. These can be overridden for each partition (both for index and overow data segment). The tablespace for index segment, if not specied for a partition, is set to the table level default. If the table level default is not specied, then the default tablespace for the user is used. The default values for PCTTHRESHOLD and INCLUDING column can only be specied at the table level. All the attributes that are specied before the OVERFLOW keyword apply to primary index segments. All the attributes specied after the OVERFLOW keyword apply to overow data segments. The tablespace for an overow data segment, if not specied for a partition, is set to the table-level default. If the table-level default is not specied, the tablespace of the corresponding partitions index segment is used.
The following example continues the example of the docindex table. It illustrates a range partition on token values.
CREATE TABLE Docindex4 (Token CHAR(20), Doc_id NUMBER, Token_frequency NUMBER, Token_offsets VARCHAR(512), CONSTRAINT Pk_docindex4 PRIMARY KEY (Token, Doc_id) ) ORGANIZATION INDEX INITRANS 4 INCLUDING Token_frequency OVERFLOW INITRANS 6 PARTITION BY RANGE(token) ( PARTITION P1 VALUES LESS THAN (j) TABLESPACE Ind_ts0 OVERFLOW TABLESPACE Ov_ts0, PARTITION P2 VALUES LESS THAN (s) TABLESPACE Ind_ts1 OVERFLOW TABLESPACE Ov_ts1, PARTITION P3 VALUES LESS THAN (MAXVALUE) TABLESPACE Ind_ts2 OVERFLOW TABLESPACE Ov_ts2);
This creates the table shown in Figure 64. The INCLUDING clause stores the token_offsets column in the overow data segment for each partition.
ind_ts0
ind_ts1
ind_ts2
ov_ts0
ov_ts1
ov_ts2
Partitioned indexes on index-organized tables are supported. Local prexed, local non-prexed, and global prexed partitioned indexes are supported on index-organized tables. The only difference is that these indexes store logical rowids instead of physical rowids. All of the ALTER TABLE operations are available for partitioned index-organized tables. These operations are slightly different with index-organized tables than with ordinary tables:
s
For ALTER TABLE MOVE partition operations, all indexeslocal, global, and non-partitionedremain USABLE because the indexes contain logical rowids. However, the guess stored in the logical rowid becomes invalid. For SPLIT partition operations, all non-partitioned indexes or global index partitions remain usable. For ALTER TABLE EXCHANGE partition, the target table must be a compatible index-organized table. Users can use the ALTER TABLE ADD OVERFLOW command to add an overow segment and specify table-level default and partition-level physical and storage attributes. This operation results in adding an overow data segment to each partition.
6-18
ALTER INDEX operations are very similar to those on ordinary tables. The only difference is that operations that reconstruct the entire indexnamely, ALTER INDEX REBUILD and SPLIT_PARTITIONresult in reconstructing the guess stored as part of the logical rowid. New ALTER INDEX UPDATE BLOCK REFERENCES syntax xes the invalid physical guesses without reconstructing the indexes. Query and DML operations on partitioned index-organized tables work the same as on ordinary partitioned tables.
Common prexes of length 1 (that is, token column) are compressed in the primary key (token, doc_id) occurrences. For the list of primary key values (DBMS, 1), (DBMS, 2), (Oracle, 1), (Oracle, 2), the repeated occurrences of DBMS and Oracle are compressed away. If a prex length is not specied, by default it is set to the number of primary key columns minus 1. You can specify the compress option when creating an index-organized table or when moving an index-organized table using ALTER TABLE MOVE. For example, you can disable compression as follows:
ALTER TABLE Docindex5 MOVE NOCOMPRESS;
Similarly, the indexes for ordinary tables and index-organized tables can be compressed using the COMPRESS option. Compressing the Keys for Partitioned Index-Organized Tables: Example You can also compress the keys for partitioned index-organized tables, by specifying the
compression clause as part of the table-level defaults. Compression can be enabled or disabled for each partition. The prex length cannot be changed at the partition level.
CREATE TABLE Docindex6 ( Token CHAR(20), Doc_id NUMBER, Token_frequency NUMBER, Token_offsets VARCHAR(512), CONSTRAINT Pk_docindex6 PRIMARY KEY (Token, Doc_id) ) ORGANIZATION INDEX INITRANS 4 COMPRESS 1 INCLUDING Token_frequency OVERFLOW INITRANS 6 PARTITION BY RANGE(Token) ( PARTITION P1 VALUES LESS THAN (j) TABLESPACE Ind_ts0 OVERFLOW TABLESPACE Ov_ts0, PARTITION P2 VALUES LESS THAN (s) TABLESPACE Ind_ts1 NOCOMPRESS OVERFLOW TABLESPACE Ov_ts1, PARTITION P3 VALUES LESS THAN (MAXVALUE) TABLESPACE Ind_ts2 OVERFLOW TABLESPACE Ov_ts2 );
All partitions inherit the table-level default for prex length. Partitions P1 and P3 are created with key-compression enabled. For partition P2, the compression is disabled by the partition level NOCOMPRESS option. For ALTER TABLE MOVE and SPLIT operations, the COMRPESS option can be altered. The following example rebuilds the partition with key compression enabled.
ALTER TABLE Docindex6 MOVE PARTITION P2 COMPRESS;
The OVERFLOW clause is explicitly specied, The PCTHRESHOLD and/or INCLUDING column value are altered as part of the MOVE statement. Any LOBs are moved explicitly
6-20
By default, LOB columns related to index and data segments are not rebuilt, except when the LOB columns are explicitly specied as part of the MOVE statement. The following example rebuilds the B*-tree index containing the table data after setting INITRANS to 6 for index blocks.
ALTER TABLE docindex MOVE INITRANS 6;
The following example rebuilds both the primary key index and overow data segment.
ALTER TABLE docindex MOVE TABLESPACE Ovf_tbs OVERFLOW TABLESPACE ov_ts0;
By default, during the move, the table is not available for other operations. However, you can move an index-organized table using the ONLINE option. The following example allows the table to be available for DML and query operations during the actual move operation. This feature makes the index-organized table suitable for applications requiring 24x7 availability.
Caution: You may need to set your COMPATIBLE initialization parameter to 8.1.3.0 or higher to get the following to work.
ALTER TABLE Docindex MOVE ONLINE;
ONLINE move is supported only for index-organized tables that do not have an overow segment.
6-22
7
How Oracle Processes SQL Statements
This chapter describes how Oracle processes Structured Query Language (SQL) statements. Topics include the following:
s
Overview of SQL Statement Execution Grouping Operations into Transactions Ensuring Repeatable Reads with Read-Only Transactions Using Cursors within Applications Locking Data Explicitly Explicitly Acquiring Row Locks Letting Oracle Control Table Locking About User Locks Using Serializable Transactions for Concurrency Control Autonomous Transactions Resuming Execution After a Storage Error Condition Querying Data at a Point in Time (Flashback Query)
Although some Oracle tools and applications simplify or mask the use of SQL, all database operations are performed using SQL, to take advantage of the security and data integrity features built into Oracle.
each stage of SQL statement processing for each type of SQL statement.
7-2
OPEN PARSE
query?
yes
describe?
yes
DESCRIBE
no
yes
bind?
no
no
more?
yes
EXECUTE PARALLELIZE
query?
yes
FETCH
more?
Use the BEGIN_DISCRETE_TRANSACTION procedure to improve the performance of short, non-distributed transactions. Use the SET TRANSACTION command with the USE ROLLBACK SEGMENT parameter to explicitly assign a transaction to an appropriate rollback segment. This can eliminate the need to dynamically allocate additional extents, which can reduce overall system performance. Use the SET TRANSACTION command with the ISOLATION LEVEL set to SERIALIZABLE to get ANSI/ISO serializable transactions.
See Also:
s s
Establish standards for writing SQL statements so that you can take advantage of shared SQL areas. Oracle recognizes identical SQL statements and allows
7-4
them to share memory areas. This reduces memory usage on the database server and increases system throughput.
s
Use the ANALYZE command to collect statistics that can be used by Oracle to implement a cost-based approach to SQL statement optimization. You can supply additional "hints" to the optimizer as needed. Call the DBMS_APPLICATION_INFO.SET_ACTION procedure before beginning a transaction to register and name a transaction for later use when measuring performance across an application. You should specify what type of activity a transaction performs so that the system tuners can later see which transactions are taking up the most system resources. Increase user productivity and query efciency by including user-written PL/SQL functions in SQL expressions as described in "Calling Stored Functions from SQL Expressions". Create explicit cursors when writing a PL/SQL application. When writing precompiler programs, increasing the number of cursors using MAX_OPEN_CURSORS can often reduce the frequency of parsing and improve performance.
See Also: "Using Cursors within Applications" on page 7-9
Committing Transactions
To commit a transaction, use the COMMIT command. The following two statements are equivalent and commit the current transaction:
COMMIT WORK; COMMIT;
The COMMIT command lets you include the COMMENT parameter along with a comment (less than 50 characters) that provides information about the transaction being committed. This option is useful for including information about the origin of the transaction when you commit distributed transactions:
COMMIT COMMENT Dallas/Accts_pay/Trans_type 10B;
The WORK option of the ROLLBACK command has no function. To roll back to a savepoint dened in the current transaction, use the TO option of the ROLLBACK command. For example, either of the following statements rolls back the current transaction to the savepoint named POINT1:
SAVEPOINT Point1; ... ROLLBACK TO SAVEPOINT Point1; ROLLBACK TO Point1;
If you create a second savepoint with the same identier as an earlier savepoint, the earlier savepoint is erased. After creating a savepoint, you can roll back to the savepoint. There is no limit on the number of active savepoints for each session. An active savepoint is one that has been specied since the last commit or rollback.
7-6
SQL Statement SAVEPOINT a; DELETE...; SAVEPOINT b; INSERT INTO...; SAVEPOINT c; UPDATE...; ROLLBACK TO c; ROLLBACK TO b; ROLLBACK TO c; INSERT INTO...; COMMIT;
Results First savepoint of this transaction First DML statement of this transaction Second savepoint of this transaction Second DML statement of this transaction Third savepoint of this transaction Third DML statement of this transaction. UPDATE statement is rolled back, savepoint C remains dened INSERT statement is rolled back, savepoint C is lost, savepoint B remains dened ORA-01086 error; savepoint C no longer dened New DML statement in this transaction Commits all actions performed by the rst DML statement (the DELETE statement) and the last DML statement (the second INSERT statement) All other statements (the second and the third statements) of the transaction were rolled back before the COMMIT. The savepoint A is no longer active.
The SET TRANSACTION statement must be the rst statement of a new transaction; if any DML statements (including queries) or other non-DDL statements (such as SET ROLE) precede a SET TRANSACTION READ ONLY statement, an error is returned. Once a SET TRANSACTION READ ONLY statement successfully executes, only SELECT (without a FOR UPDATE clause), COMMIT, ROLLBACK, or non-DML statements (such as SET ROLE, ALTER SYSTEM, LOCK TABLE) are allowed in the transaction. Otherwise, an error is returned. A COMMIT, ROLLBACK, or DDL statement terminates the read-only transaction; a DDL statement causes an implicit commit of the read-only transaction and commits in its own transaction.
7-8
Each cursor requires virtual memory, so a sessions total number of cursors is limited by the memory available to that process. A system-wide limit of cursors for each session is set by the initialization parameter named OPEN_CURSORS found in the parameter le (such as INIT.ORA).
See Also: Parameters are described in Oracle9i Database Reference.
Explicitly creating cursors for precompiler programs can offer some advantages in tuning those applications. For example, increasing the number of cursors can often reduce the frequency of parsing and improve performance. If you know how many cursors may be required at a given time, then you can make sure you can open that many simultaneously.
By opening several cursors, the parsed representation of several SQL statements can be saved. Repeated execution of the same SQL statements can thus begin at the describe, dene, bind, or execute step, saving the repeated cost of opening cursors and parsing. To understand the performance characteristics of a cursor, a DBA can retrieve the text of the query represented by the cursor using the V$SQL catalog view. Because the results of EXPLAIN PLAN on the original query might differ from the way the query is actually processed, the DBA can get more precise information by examining the V$SQL_PLAN and V$SQL_PLAN_STATS catalog views. The V$SQL_PLAN_ENV catalog view shows what parameters have changed from their default values, which might cause the EXPLAIN PLAN output to differ from the actual execution plan for the cursor.
See Also: Oracle9i Database Reference. for details about each of these catalog views.
Closing Cursors
Closing a cursor means that the information currently in the associated private area is lost and its memory is deallocated. Once a cursor is opened, it is not closed until one of the following events occurs:
s
The user program terminates its connection to the server. If the user program is an OCI program or precompiler application, then it explicitly closes any open cursor during the execution of that program. (However, when this program terminates, any cursors remaining open are implicitly closed.)
Cancelling Cursors
Cancelling a cursor frees resources from the current fetch.The information currently in the associated private area is lost but the cursor remains open, parsed, and associated with its bind variables.
Note: You cannot cancel cursors using Pro*C or PL/SQL.
7-10
You want transaction-level read consistency or "repeatable reads"where transactions query a consistent set of data for the duration of the transaction, knowing that the data has not been changed by any other transactions. This level of consistency can be achieved by using explicit locking, read-only transactions, serializable transactions, or overriding default locking for the system. A transaction requires exclusive access to a resource. To proceed with its statements, the transaction with exclusive access to a resource does not have to wait for other transactions to complete.
How to Enable
transaction level
Transactions including the following SQL statements override Oracles default locking: the LOCK TABLE command, the SELECT command including the FOR UPDATE clause, and the SET TRANSACTION command with the READ ONLY or ISOLATION LEVEL SERIALIZABLE options. Locks acquired by these statements are released after the transaction is committed or rolled back. An instance can be started with nondefault locking by adjusting the initialization parameters SERIALIZABLE and ROW_LOCKING.
system level
The following sections describe each option available for overriding the default locking of Oracle. The initialization parameter DML_LOCKS determines the maximum number of DML locks allowed.
See Also:
parameters.
Although the default value is usually enough, you might need to increase it if you use additional manual locks.
Caution: If you override the default locking of Oracle at any
level, be sure that the overriding locking procedures operate correctly: Ensure that data integrity is guaranteed, data concurrency is acceptable, and deadlocks are not possible or are appropriately handled.
You can specify several tables or views to lock in the same mode; however, only a single lock mode can be specied for each LOCK TABLE statement.
Note: When a table is locked, all rows of the table are locked. No
other user can modify the table. You can also indicate if you do or do not want to wait to acquire the lock. If you specify the NOWAIT option, then you only acquire the table lock if it is immediately available. Otherwise an error is returned to notify that the lock is not available at this time. In this case, you can attempt to lock the resource at a later time. If NOWAIT is omitted, then the transaction does not proceed until the requested table lock is acquired. If the wait for a table lock is excessive, then you might want to cancel the lock operation and retry at a later time; you can code this logic into your applications.
7-12
ROW SHARE and ROW EXCLUSIVE table locks offer the highest degree of concurrency. You might use these locks if:
s
Your transaction needs to prevent another transaction from acquiring an intervening share, share row, or exclusive table lock for a table before the table can be updated in your transaction. If another transaction acquires an intervening share, share row, or exclusive table lock, no other transactions can update the table until the locking transaction commits or rolls back. Your transaction needs to prevent a table from being altered or dropped before the table can be modied later in your transaction.
SHARE table locks are rather restrictive data locks. You might use these locks if:
s
Your transaction only queries the table, and requires a consistent set of the tables data for the duration of the transaction. You can hold up other transactions that try to update the locked table, until all transactions that hold SHARE locks on the table either commit or roll back. Other transactions may acquire concurrent SHARE table locks on the same table, also allowing them the option of transaction-level read consistency.
Caution: Your transaction may or may not update the table later
in the same transaction. However, if multiple transactions concurrently hold share table locks for the same table, no transaction can update the table (even if row locks are held as the result of a SELECT... FOR UPDATE statement). Therefore, if concurrent share table locks on the same table are common, updates cannot proceed and deadlocks are common. In this case, use share row exclusive or exclusive table locks instead. For example, assume that two tables, EMP_TAB and BUDGET_TAB, require a consistent set of data in a third table, DEPT_TAB. For a given department number, you want to update the information in both of these tables, and ensure that no new members are added to the department between these two transactions. Although this scenario is quite rare, it can be accommodated by locking the DEPT_TAB table in SHARE MODE, as shown in the following example. Because the
DEPT_TAB table is rarely updated, locking it probably does not cause many other transactions to wait long.
Note: You may need to set up data structures similar to the
LOCK TABLE Dept_tab IN SHARE MODE; UPDATE Emp_tab SET sal = sal * 1.1 WHERE deptno IN (SELECT deptno FROM Dept_tab WHERE loc = DALLAS); UPDATE Budget_tab SET Totsal = Totsal * 1.1 WHERE Deptno IN (SELECT Deptno FROM Dept_tab WHERE Loc = DALLAS); COMMIT; /* This releases the lock */
7-14
Your transaction requires both transaction-level read consistency for the specied table and the ability to update the locked table. You do not care if other transactions acquire explicit row locks (using SELECT... FOR UPDATE), which might make UPDATE and INSERT statements in the locking transaction wait and might cause deadlocks. You only want a single transaction to have the above behavior.
Your transaction requires immediate update access to the locked table. When your transaction holds an exclusive table lock, other transactions cannot lock specic rows in the locked table. Your transaction also ensures transaction-level read consistency for the locked table until the transaction is committed or rolled back. You are not concerned about low levels of data concurrency, making transactions that request exclusive table locks wait in line to update the table sequentially.
Privileges Required
You can automatically acquire any type of table lock on tables in your schema. To acquire a table lock on a table in another schema, you must have the LOCK ANY TABLE system privilege or any object privilege (for example, SELECT or UPDATE) for the table.
Table locks are also controlled by the ROW_LOCKING and SERIALIZABLE initialization parameters. By default, SERIALIZABLE is set to FALSE and ROW_LOCKING is set to ALWAYS. In almost every case, these parameters should not be altered. They are provided for sites that must run in ANSI/ISO compatible mode, or that want to use applications written to run with earlier versions of Oracle. Only these sites should consider altering these parameters, as there is a signicant performance degradation caused by using other than the defaults.
See Also: Oracle9i SQL Reference for details about the SET
TRANSACTION and ALTER SESSION statements. The settings for these parameters should be changed only when an instance is shut down. If multiple instances are accessing a single database, then all instances should use the same setting for these parameters.
Case Description 1 Equivalent to Version 5 and earlier Oracle releases (no concurrent inserts, updates, or deletes in a table) ANSI compatible ANSI compatible, with table-level locking (no concurrent inserts, updates, or deletes in a table)
2 3
ALWAYS INTENT
Table 72 illustrates the difference in locking behavior resulting from the three possible settings of the SERIALIZABLE option and ROW_LOCKING initialization parameter, as shown in Table 71.
7-16
Statement SELECT INSERT UPDATE DELETE SELECT...FOR UPDATE LOCK TABLE... IN.. ROW SHARE MODE ROW EXCLUSIVE MODE SHARE MODE
If a SELECT... FOR UPDATE statement is used when dening a cursor, the rows in the return set are locked when the cursor is opened (before the rst fetch) rather than as they are fetched from the cursor. Locks are only released when the transaction that opened the cursor is committed or rolled back, not when the cursor is closed. Each row in the return set of a SELECT... FOR UPDATE statement is locked individually; the SELECT... FOR UPDATE statement waits until the other transaction releases the conicting row lock. If a SELECT... FOR UPDATE statement locks many rows in a table, and if the table experiences a lot of update activity, it might be faster to acquire an EXCLUSIVE table lock instead. When acquiring row locks with SELECT... FOR UPDATE, you can specify the NOWAIT option to indicate that you are not willing to wait to acquire the lock. If you cannot acquire then lock immediately, an error is returned to signal that the lock is not possible at this time. You can try to lock the row again later. By default, the transaction waits until the requested row lock is acquired. If the wait for a row lock is too long, you can code logic into your application to cancel the lock operation and try again later.
Provide exclusive access to a device, such as a terminal Provide application-level enforcement of read locks Detect when a lock is released and cleanup after the application Synchronize applications and enforce sequential processing
7-18
Unlock the printer so other people can use it EXEC SQL EXECUTE BEGIN DBMS_LOCK.RELEASE ( :LOCKHANDLE ); END; END-EXEC.
Description
The Monitor feature of Enterprise Manager provides two monitors for displaying lock information of an instance. Refer to Oracle Enterprise Manager Administrators Guide for complete information about the Enterprise Manager monitors. The UTLLOCKT.SQL script displays a simple character lock wait-for graph in tree structured fashion. Using any ad hoc SQL tool (such as SQL*Plus) to execute the script, it prints the sessions in the system that are waiting for locks and the corresponding blocking locks. The location of this script le is operating system dependent. (You must have run the CATBLOCK.SQL script before using UTLLOCKT.SQL.)
7-20
The ANSI/ISO SQL standard SQL92 denes three possible kinds of transaction interaction, and four levels of isolation that provide increasing protection against these interactions. These interactions and isolation levels are summarized in Table 73.
Table 73 Summary of ANSI Isolation Levels
Dirty Read (1) Possible Not possible Not possible Not possible Non-Repeatable Read (2) Possible Possible Not possible Not possible Phantom Read (3) Possible Possible Possible Not possible
Isolation Level READ UNCOMMITTED READ COMMITTED REPEATABLE READ SERIALIZABLE Notes:
(1) A transaction can read uncommitted data changed by another transaction. (2) A transaction rereads data committed by another transaction and sees the new data. (3) A transaction can execute a query again, and discover new rows inserted by another committed transaction.
The behavior of Oracle with respect to these isolation levels is summarized below:
Isolation Level Description
READ UNCOMMITTED
Oracle never permits "dirty reads." Although some other database products use this undesirable technique to improve thoughput, it is not required for high throughput with Oracle. Oracle meets the READ COMMITTED isolation standard. This is the default mode for all Oracle applications. Because an Oracle query only sees data that was committed at the beginning of the query (the snapshot time), Oracle actually offers more consistency than is required by the ANSI/ISO SQL92 standards for READ COMMITTED isolation. Oracle does not normally support this isolation level, except as provided by SERIALIZABLE.
READ COMMITTED
REPEATABLE READ
Isolation Level
Description
SERIALIZABLE
You can set this isolation level using the SET TRANSACTION command or the ALTER SESSION command.
7-22
Figure 72
TRANSACTION A (arbitrary)
begin work update row 2 in block 1 Issue update "too recent" for B to see
insert row 4
commit
B can see its own changes but not the committed changes of transaction A.
re-read updated row 1 in block 1 search for row 4 (not found) read old row 2 in block 1
TIME
Failure on attempt to update row updated & committed since transaction B began
Commit the work executed to that point Execute additional, different, statements, perhaps after rolling back to a prior savepoint in the transaction Roll back the entire transaction and try it again
Oracle stores control information in each data block to manage access by concurrent transactions. To use the SERIALIZABLE isolation level, you must use the INITRANS clause of the CREATE TABLE or ALTER TABLE command to set aside storage for this control information. To use serializable mode, INITRANS must be set to at least 3.
7-24
Figure 73
TRANSACTION A
TRANSACTION B
delete parent
commit work
commit work
The read issued by transaction A does not prevent transaction B from deleting the parent row, and transaction Bs query for child rows does not prevent transaction A from inserting child rows. This scenario leaves a child row in the database with no corresponding parent row. This result occurs even if both A and B are SERIALIZABLE transactions, because neither transaction prevents the other from making changes in the data it reads to check consistency. As this example shows, sometimes you must take steps to ensure that the data read by one transaction is not concurrently written by another. This requires a greater degree of transaction isolation than dened by SQL92 SERIALIZABLE mode.
7-26
Transaction A can use SELECT FOR UPDATE to query and lock the parent row and thereby prevent transaction B from deleting the row. Transaction B can prevent Transaction A from gaining access to the parent row by reversing the order of its processing steps. Transaction B rst deletes the parent row, and then rolls back if its subsequent query detects the presence of corresponding rows in the child table.
Referential integrity can also be enforced in Oracle using database triggers, instead of a separate query as in Transaction A above. For example, an INSERT into the child table can re a BEFORE INSERT row-level trigger to check for the corresponding parent row. The trigger queries the parent table using SELECT FOR UPDATE, ensuring that parent row (if it exists) remains in the database for the duration of the transaction inserting the child row. If the corresponding parent row does not exist, the trigger rejects the insert of the child row. SQL statements issued by a database trigger execute in the context of the SQL statement that caused the trigger to re. All SQL statements executed within a trigger see the database in the same state as the triggering statement. Thus, in a READ COMMITTED transaction, the SQL statements in a trigger see the database as of the beginning of the triggering statements execution, and in a transaction executing in SERIALIZABLE mode, the SQL statements see the database as of the beginning of the transaction. In either case, the use of SELECT FOR UPDATE by the trigger correctly enforces referential integrity.
A collection of database tables (or any set of data) A sequence of reads of rows in those tables The set of transactions committed at any moment
An operation (a query or a transaction) is transaction set consistent if its read operations all return data written by the same set of committed transactions. When an operation is not transaction set consistent, some reads reect the changes of one set of transactions, and other reads reect changes made by other transactions. Such an operation sees the database in a state that reects no single set of committed transactions. Oracle transactions executing in READ COMMITTED mode are transaction set consistent on a per-statement basis, because all rows read by a query must be committed before the query begins. Oracle transactions executing in SERIALIZABLE mode are transaction set consistent on a per-transaction basis, because all statements in a SERIALIZABLE transaction execute on an image of the database as of the beginning of the transaction. In other database systems, a single query run in READ COMMITTED mode provides results that are not transaction set consistent. The query is not transaction set consistent, because it may see only a subset of the changes made by another transaction. For example, a join of a master table with a detail table could see a master record inserted by another transaction, but not the corresponding details inserted by that transaction, or vice versa. Oracles READ COMMITTED mode avoids this problem, and so provides a greater degree of consistency than read-locking systems. In read-locking systems, at the cost of preventing concurrent updates, SQL92 REPEATABLE READ isolation provides transaction set consistency at the statement level, but not at the transaction level. The absence of phantom protection means two queries issued by the same transaction can see data committed by different sets of other transactions. Only the throughput-limiting and deadlock-susceptible SERIALIZABLE mode in these systems provides transaction set consistency at the transaction level.
7-28
Table 74
Operation Dirty write Dirty read
Non-repeatable read Phantoms Compliant with ANSI/ISO SQL 92 Read snapshot time Transaction set consistency Row-level locking Readers block writers Writers block readers Different-row writers block writers Same-row writers block writers Waits for blocking transaction Subject to "cant serialize access" error Error after blocking transaction aborts Error after blocking transaction commits
Both Oracle isolation modes provide high levels of consistency and concurrency (and performance) through the combination of row-level locking and Oracles multi-version concurrency control system. Because readers and writers do not block one another in Oracle, while queries still see consistent data, both READ COMMITTED and SERIALIZABLE isolation provide a high level of concurrency for high performance, without the need for reading uncommitted ("dirty") data. READ COMMITTED isolation can provide considerably more concurrency with a somewhat increased risk of inconsistent results (due to phantoms and non-repeatable reads) for some transactions. The SERIALIZABLE isolation level provides somewhat more consistency by protecting against phantoms and non-repeatable reads, and may be important where a read/write transaction executes a query more than once. However, SERIALIZABLE mode requires applications to check for the "cant serialize access" error, and can signicantly reduce throughput in an environment with many concurrent transactions accessing the same data for update. Application logic that checks database consistency must take into account the fact that reads do not block writes in either mode.
When you get this error, roll back the current transaction and execute it again. The transaction gets a new transaction snapshot, and the operation is likely to succeed. To minimize the performance overhead of rolling back transactions and executing them again, try to put DML statements that might conict with other concurrent transactions near the beginning of your transaction.
7-30
Autonomous Transactions
Autonomous Transactions
This section gives a brief overview of autonomous transactions and what you can do with them.
See Also: For detailed information on autonomous transactions,
see PL/SQL Users Guide and Reference and Chapter 15, "Using Triggers". At times, you may want to commit or roll back some changes to a table independently of a primary transactions nal outcome. For example, in a stock purchase transaction, you may want to commit a customers information regardless of whether the overall stock purchase actually goes through. Or, while running that same transaction, you may want to log error messages to a debug table even if the overall transaction rolls back. Autonomous transactions allow you to do such tasks. An autonomous transaction (AT) is an independent transaction started by another transaction, the main transaction (MT). It lets you suspend the main transaction, do SQL operations, commit or roll back those operations, then resume the main transaction. An autonomous transaction executes within an autonomous scope. An autonomous scope is a routine you mark with the pragma (compiler directive) AUTONOMOUS_TRANSACTION. The pragma instructs the PL/SQL compiler to mark a routine as autonomous (independent). In this context, the term routine includes:
s
Top-level (not nested) anonymous PL/SQL blocks Local, standalone, and packaged functions and procedures Methods of a SQL object type PL/SQL triggers
Figure 74 shows how control ows from the main routine (MT) to an autonomous routine (AT) and back again. As you can see, the autonomous routine can commit more than one transaction (AT1 and AT2) before control returns to the main routine.
Autonomous Transactions
Autonomous Routine
PROCEDURE proc2 IS PRAGMA AUTON... dept_id NUMBER; BEGIN dept_id := 20; UPDATE ... INSERT ... UPDATE ... COMMIT; INSERT ... INSERT ... COMMIT; END;
MT begins
MT ends
When you enter the executable section of an autonomous routine, the main transaction suspends. When you exit the routine, the main transaction resumes. COMMIT and ROLLBACK end the active autonomous transaction but do not exit the autonomous routine. As Figure 74 shows, when one transaction ends, the next SQL statement begins another transaction. A few more characteristics of autonomous transactions:
s
The changes autonomous transactions effect do not depend on the state or the eventual disposition of the main transaction. For example: An autonomous transaction does not see any changes made by the main transaction. When an autonomous transaction commits or rolls back, it does not affect the outcome of the main transaction.
The changes an autonomous transaction effects are visible to other transactions as soon as that autonomous transaction commits. This means that users can access the updated information without having to wait for the main transaction to commit. Autonomous transactions can start other autonomous transactions.
Figure 75 illustrates some of the possible sequences autonomous transactions can follow.
7-32
Autonomous Transactions
A main transaction scope (MT Scope) begins the main transaction, MTx. MTx invokes the first autonomous transaction scope (AT Scope1). MTx suspends. AT Scope 1 begins the transaction Tx1.1. At Scope 1 commits or rolls back Tx1.1, than ends. MTx resumes. MTx invokes AT Scope 2. MT suspends, passing control to AT Scope 2 which, initially, is performing queries. AT Scope 2 then begins Tx2.1 by, say, doing an update. AT Scope 2 commits or rolls back Tx2.1. Later, AT Scope 2 begins a second transaction, Tx2.2, then commits or rolls it back. AT Scope 2 performs a few queries, then ends, passing control back to MTx. MTx invokes AT Scope 3. MTx suspends, AT Scope 3 begins. AT Scope 3 begins Tx3.1 which, in turn, invokes AT Scope 4. Tx3.1 suspends, AT Scope 4 begins. AT Scope 4 begins Tx4.1, commits or rolls it back, then ends. AT Scope 3 resumes. AT Scope 3 commits or rolls back Tx3.1, then ends. MTx resumes. Finally, MT Scope commits or rolls back MTx, then ends.
MT Scope MTx
AT Scope 1
AT Scope 2
AT Scope 3
AT Scope 4
Tx1.1 MTx
Tx2.1
Tx2.2
MTx
Tx3.1
Tx4.1
Tx3.1 MTx
Autonomous Transactions
7-34
Autonomous Transactions
MT Scope begins the main transaction, MTx inserts the buy order into a table. MTx invokes the autonomous transaction scope (AT Scope). When AT Scope begins, MT Scope suspends. ATx, updates the audit table with customer information. MTx seeks to validate the order, finds that the selected item is unavailable, and therefore rolls back the main transaction.
MT Scope MTx
AT Scope
ATx
MTx
Scenario 1: There are sufcient funds to cover the withdrawal and therefore the bank releases the funds Scenario 2: There are insufcient funds to cover the withdrawal, but the customer has overdraft protection. The bank therefore releases the funds. Scenario 3: There are insufcient funds to cover the withdrawal, the customer does not have overdraft protection, and the bank therefore withholds the requested funds.
Autonomous Transactions
Scenario 1:
There are sufcient funds to cover the withdrawal and therefore the bank releases the funds
Figure 77 Example: Bank WithdrawalSufcient Funds
MT Scope MTx
AT Scope 1
AT Scope 2
Tx1.1 inserts the transaction ID into the audit table and commits.
Tx1.1
MTx
Tx2.1, updates the audit table using the transaction ID generated above, then commits.
Tx2.1
MTx
7-36
Autonomous Transactions
Scenario 2:
There are insufcient funds to cover the withdrawal, but the customer has overdraft protection. The bank therefore releases the funds.
Figure 78 Example: Bank WithdrawalInsufcient Funds WITH Overdraft Protection
MT Scope MTx
AT Scope 1
AT Scope 2
Tx1.1
MTx discovers that there are insufficient funds to cover the withdrawal. It finds that the customer has overdraft protection and sets a flag to the appropriate value. Tx2.1, updates the audit table.
MTx
Tx2.1
MTx
Autonomous Transactions
Scenario 3:
There are insufcient funds to cover the withdrawal, the customer does not have overdraft protection, and the bank therefore withholds the requested funds.
Figure 79 Example: Bank WithdrawalInsufcient Funds WITHOUT Overdraft Protection
MT Scope MTx
AT Scope 1
AT Scope 2
Tx1.1
MTx discovers that there are insufficient funds to cover the withdrawal. It finds that the customer does not have overdraft protection and sets a flag to the appropriate value. Tx2.1, updates the audit table.
MTx
Tx2.1
MTx Scope rolls back MTx, denying the release of funds. MT Scope ends.
MTx
7-38
Autonomous Transactions
understanding of autonomous transactions. For a more thorough understanding of autonomous transactions, see PL/SQL Users Guide and Reference. To dene autonomous transactions, you use the pragma (compiler directive) AUTONOMOUS_TRANSACTION. The pragma instructs the PL/SQL compiler to mark the procedure, function, or PL/SQL block as autonomous (independent). You can code the pragma anywhere in the declarative section of a procedure, function, or PL/SQL block. But, for readability, code the pragma at the top of the section. The syntax follows:
PRAGMA AUTONOMOUS_TRANSACTION;
You cannot use the pragma to mark all subprograms in a package (or all methods in an object type) as autonomous. Only individual routines can be marked autonomous. For example, the following pragma is illegal:
CREATE OR REPLACE PACKAGE Banking AS PRAGMA AUTONOMOUS_TRANSACTION; -- illegal FUNCTION Balance (Acct_id INTEGER) RETURN REAL; END Banking;
Out of space errors, such as ORA-01653. Space limit errors, such as ORA-01628. Space quota errors, such as ORA-01536.
7-40
Parse the error message with the DBMS_RESUMABLE.SPACE_ERROR_INFO function. For details about this function, see Oracle9i Supplied PL/SQL Packages and Types Reference. Set a new timeout value with the SET_TIMEOUT procedure.
Within the body of the trigger, you can perform any notications, such as sending a mail message to alert an operator to the space problem. Alternatively, the DBA can periodically check for suspended statements using the data dictionary views DBA_RESUMABLE, USER_RESUMABLE, and V$_SESSION_WAIT. When the space condition is corrected (usually by the DBA), the suspended statement automatically resumes execution. If it is not corrected before the timeout period expires, the operation causes a SERVERERROR exception. To reduce the chance of out-of-space errors within the trigger itself, you must declare it as an autonomous transaction so that it uses a rollback segment in the SYSTEM tablespace. If the trigger encounters a deadlock condition because of locks held by the suspended statement, the trigger is aborted and your application receives the original error condition, as if it was never suspended. If the trigger encounters an out-of-space condition, the trigger and the suspended statement are rolled back. You can prevent the rollback through an exception handler in the trigger, and just wait for the statement to be resumed.
See Also: Oracle9i Database Reference for details on the DBA_RESUMABLE, USER_RESUMABLE, and V$_SESSION_WAIT data dictionary views.
object_owner VARCHAR2(64); object_type VARCHAR2(64); table_space_name VARCHAR2(64); object_name VARCHAR2(64); sub_object_name VARCHAR2(64); msg_body VARCHAR2(64); ret_value boolean; error_txt varchar2(64); mail_conn utl_smtp.connection; BEGIN SELECT DISTINCT(sid) INTO cur_sid FROM v$mystat; cur_inst := userenv('instance'); ret_value := dbms_resumable.space_error_info(err_type, object_owner, object_type, table_space_name, object_name, sub_object_name); IF object_type = 'ROLLBACK SEGMENT' THEN INSERT INTO sys.rbs_error ( SELECT sql_text, error_msg, suspend_time FROM dba_resumable WHERE session_id = cur_sid AND instance_id = cur_inst); SELECT error_msg into error_txt FROM dba_resumable WHERE session_id = cur_sid AND instance_id = cur_inst; msg_body := 'Subject: Space error occurred: Space limit reached for rollback segment '|| object_name || ' on ' || to_char(SYSDATE, 'Month dd, YYYY, HH:MIam') || '. Error message was: ' || error_txt; mail_conn := utl_smtp.open_connection('localhost', 25); utl_smtp.helo(mail_conn, 'localhost'); utl_smtp.mail(mail_conn, 'sender@localhost'); utl_smtp.rcpt(mail_conn, 'recipient@localhost'); utl_smtp.data(mail_conn, msg_body); utl_smtp.quit(mail_conn); dbms_resumable.abort(cur_sid); ELSE dbms_resumable.set_timeout(3600*8); END IF; COMMIT; END;
7-42
Recovering lost data or undoing incorrect changes, even after the changes are committed. For example, a user who deletes or updates rows and then commits can immediately repair a mistake. Comparing current data against the data at some time in the past. For example, you might run a daily report that shows the change from yesterday, rather than just the current data. Checking the state of transactional data at a particular time. For example, you might want to verify an account balance on a certain day. Simplifying application design by removing the need to store some kinds of temporal data. Enabling packaged applications, such as report generation tools, to work on past versions of data.
The ashback query mechanism is most effective when you use automatic undo management. The DBA requests that undo data be kept for a specied period of time. Depending on the available storage capacity, the database might not always be able to keep all the requested undo data. If you use ashback queries, you might need to familiarize yourself with automatic undo management to understand its capabilities and limitations. Other features are available to recover lost data. The unique feature of ashback query is that you can see the data as it was in the past, then choose exactly how to process the information; you might do an analysis, undoing the changes, or capture changed data for further processing.
See Also:
s
Oracle9i Database Concepts for background information about ashback query and automatic undo management. Oracle9i Database Administrators Guide for the associated DBA responsibilities, such as setting up automatic undo management and granting privileges. Oracle9i Supplied PL/SQL Packages and Types Reference for details about the DBMS_FLASHBACK package that you can use in combination with ashback queries. Oracle9i Database Reference and Oracle9i Recovery Manager Users Guide and Reference for information about system change numbers, which are used in backup and recovery and are present in some V$ data dictionary views.
Use automatic undo management to maintain read consistency, rather than the older technique using rollback segments. In particular, the DBA should:
s
Set the UNDO_RETENTION initialization parameter to a value that represents how far in the past you might want to query. The value depends on your needs. If you only need to recover data immediately after a mistaken change is committed, the parameter can be set to a small value. If you need to recover deleted data from days before, you might need several days worth of data. Set the initialization parameter UNDO_MANAGEMENT=AUTO. Create an UNDO tablespace, with enough space to keep the required data. The more often the data is updated, the more space is required. Calculating the space requirements is a job for the DBA; you can nd the formula in the Oracle9i Database Administrators Guide.
Grant FLASHBACK privilege on appropriate tables, or FLASHBACK ANY TABLE privilege, to users, roles, or applications that need to perform ashback queries through the AS OF clause of SQL. Grant EXECUTE privilege on the DBMS_FLASHBACK package to users, roles, or applications that need to perform ashback queries using this package. Use the ALTER TABLE command with the RETENTION option to enable ashback queries on specic LOB columns, if appropriate. Because LOB
7-44
columns might require signicant amounts of storage to keep undo data, you must dene which LOB columns can be used with ashback query.
Use the AS OF clause in SQL queries to specify a past time. You can specify or omit this clause for each table, and specify different times for different tables. You can perform DDL operations such as creating and truncating tables, and DML operations such as inserts and deletes, in the same session as queries using the AS OF clause. Put calls to the DBMS_FLASHBACK package around sets of queries that apply to data at a past time, or queries whose SQL you cannot change:
s
Before doing the rst query, call DBMS_FLASHBACK.ENABLE_AT_TIME or DBMS_FLASHBACK.ENABLE_AT_SYSTEM_CHANGE_NUMBER. After doing the query, call DBMS_FLASHBACK.DISABLE. Between these calls, you can only perform queries and not any DDL or DML statements.
To use the results of a ashback query in DDL or DML statements against the current state of the database, it is simplest to use the AS OF clause inside INSERT or CREATE TABLE AS SELECT statements. If you use the DBMS_FLASHBACK package, you must open a cursor before calling DBMS_FLASHBACK.DISABLE. You can fetch results from past data from the cursor, then issue INSERT or UPDATE statements against the current state of the database. To compare current data against past data using the DBMS_FLASHBACK package, you can open a cursor with the ashback feature enabled, then disable it and open another cursor. Fetching from the rst cursor retrieves data based on the ashback time; fetching from the second cursor retrieves current data. You can store the older data in a temporary table and then use set operators such as MINUS or UNION to show differences in the data or combine past and current data.
At certain points in the application, you might call DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER. You can store the returned number, and later use it to perform ashback queries against the data at that point in time. Perform a COMMIT before calling this procedure, so that the database is in a consistent state to which you can return.
Some DDLs that alter the structure of a table, such as drop/modify column, move table, drop partition, truncate table/partition, and so on, invalidate the old undo data for the table. It is not possible to retrieve a snapshot of data from a point earlier than the time such DDLs were executed. Trying such a query results in a ORA-1466 error. This restriction does not apply to DDL operations that alter the storage attributes of a table, such as PCTFREE, INITTRANS, MAXTRANS, and so on. The time specied in DBMS_FLASHBACK.ENABLE_AT_TIME or in the AS OF TIMESTAMP clause is mapped to an SCN value. Currently, the SCN-time mapping is recorded every 5 minutes after database startup. Thus, it might appear as if the specied time is being rounded down by up to 5 minutes. For example, assume that the SCN values 1000 and 1005 are mapped to the times 8:41 and 8:46 AM respectively. A ashback query for a time anywhere between 8:41:00 and 8:45:59 AM is mapped to SCN 1000; a ashback query for 8:45 AM is mapped to SCN 1005. Due to this time-to-SCN mapping, a ashback query for a time immediately after creation of a table may result in an ORA-1466 error. An SCN-based ashback query therefore gives you a more precise way to retrieve a past snapshot of data.
Because SCNs are only recorded every 5 minutes for use by ashback queries, you might specify a time or SCN that is slightly after a DDL operation, but the database might use a slightly earlier SCN that is before the DDL operation. So you might get the same error as in the previous restriction if you try to perform ashback queries to a point just after a DDL operation. Currently, the ashback query feature keeps track of times up to a maximum of 5 days. This period reects server uptime, not wall-clock time. For example, if the server is down for a day during this period, then you can specify as far back as 6 days. To query data farther back than this, you must specify an SCN rather than a date and time. You must record the SCN yourself at the time of interest, such as before doing a DELETE. When using the DBMS_FLASHBACK package, you must disable ashback before enabling it again for a different time. You cannot nest ENABLE /DISABLE pairs. You can call DISABLE multiple times in succession, although this introduces a little extra overhead, as shown in the following examples.
7-46
Only the state of table data is affected by a ashback query. During a query, the current state of the data dictionary is used. For example, if you have changed the character set since storing the data, queries use the current character set. You cannot perform a ashback query on a remote table through a database link. You cannot retrieve past data from a V$ view in the data dictionary. Performing a ashback query on such a view just returns the current data. You can perform ashback queries on other views in the data dictionary, such as USER_TABLES. The SYS user cannot make calls to the DBMS_FLASHBACK package. This user can still use the AS OF clause and perform ashback queries that way. Flashback queries against materialized views do not take advantage of query rewrite.
For good performance, generate statistics on all tables involved in ashback queries by using the DBMS_STATS package, and keep the statistics current. Flashback queries always use the cost-based optimizer, which relies on these statistics. Use the AS OF SCN clause for any operations where the data is critical, because it is not subject to the potential 5-minute rounding error. Use the AS OF TIMESTAMP clause more for ad-hoc queries and reporting, where convenience in specifying the time is more important. Because ashback queries on a table might not work for a few minutes after the table is created, make sure that to create all tables well in advance, those with the original data and any tables used for temporary storage. This tip applies more to situations where you are demonstrating or testing ashback query, rather than production environments where the tables would already be set up. While experimenting with ashback queries, you might accidentally leave your session with uncommitted data or in ashback mode. Make a habit of including a COMMIT or ROLLBACK statement (where appropriate) and a call to DBMS_FLASHBACK.DISABLE at the beginning of SQL scripts that perform ashback queries. The performance of a ashback query depends on how much data must be re-created. Use ashback query mostly for selecting small sets of data using indexes, rather than queries that require full table scans. If you must do a full table scan, consider adding a parallel hint to the query.
You can create a view that refers to past data by using the AS OF clause in the SELECT statement that denes the view. If you specify a relative time by subtracting from SYSDATE, the past time is recalculated for each query. For example:
CREATE VIEW hour_ago AS SELECT * FROM EMPLOYEES AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '60' MINUTE);
When using this technique, remember that daylight savings time and leap years can cause anomalous results. For example, SYSDATE - 1 might refer to 23 or 25 hours ago, shortly after a change in daylight savings time.
s
You can compute or retrieve the past time used in the AS OF clause, by using a function return value as the timestamp or SCN argument. For example, you can do date and time calculations by adding or subtracting an INTERVAL value to the value of the SYSTIMESTAMP function. You can use the AS OF clause in self-joins, or in set operations such as INTERSECT and MINUS, to extract or compare data from two different times. You can store the results by wrapping the queries in CREATE TABLE AS SELECT or INSERT INTO TABLE SELECT statements. Use the AS OF clause for SQL that you write, because it is exible enough to do comparisons and store results in a single query. Put calls to the DBMS_FLASHBACK package around SQL that you do not control, or when you want to use the same past time for several consecutive queries. When you use the AS OF SCN form of the clause, you use DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER rst to nd out the SCN to which to return. Remember that all processing is done using the current national language and other settings, not the ones that were in effect in the past.
Query data as it existed in the past. Compare current data to past data. You can compare individual rows, or do more complex comparisons such as nding the intersection or union. Recover deleted or changed data.
7-48
Refer to a point in time using a DATE or TIMESTAMP value, or record system change numbers.
Remember that a date with no time represents the very beginning of that day. Because of the limited amount of mapping data that is stored for times, such a query might only be able to look back a few days in the past. To look back farther, you need to store the SCN at the time of interest. Even then, the data might be unavailable if the saved undo data does not extend back that far.
------------------------- Setup ------------------------------set echo off; set serveroutput on size 50000; -- KEEP_SCN is a temporary table to store SCNs that we are interested in. DROP TABLE keep_scn; CREATE TABLE keep_scn (scn NUMBER); DELETE FROM keep_scn; COMMIT; EXECUTE dbms_flashback.disable; DROP TABLE my_employees; CREATE TABLE my_employees ( employee_no NUMBER(5) PRIMARY KEY, employee_name VARCHAR2(20), employee_mgr NUMBER(5) CONSTRAINT mgr_fkey REFERENCES my_employees ON DELETE CASCADE, salary NUMBER, hiredate DATE ); DELETE FROM my_employees; -- Now populate the company with employees. INSERT INTO my_employees values (1, 'Dennis Potter', null, 1000000, '5-jul-91'); INSERT INTO my_employees values (10, 'Margaret O''Neil', 1, 500000, '12-aug-94'); INSERT INTO my_employees values (20, 'Charles Evans', 10, 250000, '13-dec-97'); INSERT INTO my_employees values (100, 'Roger Smith', 20, 200000, '3-feb-96'); INSERT INTO my_employees values (200, 'Juan Hernandez', 100, 150000, '22-mar-98'); INSERT INTO my_employees values (210, 'Jonathan Takeda', 100, 100000, '11-apr-97'); INSERT INTO my_employees values (220, 'Nancy Schoenfeld', 100, 100000, '18-sep-95'); INSERT INTO my_employees values (300, 'Edward Ngai', 210, 75000, '4-nov-96'); INSERT INTO my_employees values (310, 'Amit Sharma', 210, 65000, '3-may-95'); COMMIT; -- Wait a little more than 5 minutes to avoid ORA-01466 error, because the -- table is so new. Only needed in demo situations like this. EXECUTE dbms_output.put_line('Pausing for 5 minutes...'); EXECUTE dbms_lock.sleep(320); ------------------------- Real work -------------------------------- Show the entire org
7-50
SELECT lpad(' ', 2*(level-1)) || employee_name "Original Org Chart" FROM my_employees CONNECT BY PRIOR employee_no = employee_mgr START WITH employee_no = 1 ORDER BY LEVEL; -- Store this snapshot for later access through FlashBack. DECLARE I number; BEGIN I := dbms_flashback.get_system_change_number; INSERT INTO keep_scn VALUES (I); COMMIT; END; / -- Now Roger decides it's time to retire, but the HR department does -- the transaction incorrectly. The DELETE CASCADE deletes Roger's organization. DELETE FROM my_employees WHERE employee_name = 'Roger Smith'; COMMIT; -- Notice that all of Roger's employees are now gone. SELECT lpad(' ', 2*(level-1)) || employee_name "Post-Roger Org Chart" FROM my_employees CONNECT BY PRIOR employee_no = employee_mgr START WITH employee_no = 1 ORDER BY LEVEL; -- Let's put back Roger's organization. DECLARE restore_scn NUMBER; rogers_emp NUMBER; rogers_mgr NUMBER; -- We use AS OF clauses on both the main query and the subquery. CURSOR c1(the_scn NUMBER) IS SELECT employee_no, employee_name, employee_mgr, salary, hiredate FROM my_employees AS OF SCN the_scn CONNECT BY PRIOR employee_no = employee_mgr START WITH employee_no = (SELECT employee_no FROM my_employees AS OF SCN the_scn WHERE employee_name = 'Roger Smith'); c1_rec c1%ROWTYPE; BEGIN SELECT scn INTO restore_scn FROM keep_scn; -- dbms_flashback.enable_at_system_change_number(restore_scn); dbms_output.put_line('Using system change number: ' || restore_scn);
SELECT employee_no, employee_mgr INTO rogers_emp, rogers_mgr FROM my_employees AS OF SCN restore_scn WHERE employee_name = 'Roger Smith'; dbms_output.put_line('Roger was employee #' || rogers_emp || ' and his manager was employee #' || rogers_mgr); -- Open c1 at the point specified by restore_scn. OPEN c1(restore_scn); -- Only the cursor uses past information, so we can insert into the original -- table within the loop. LOOP FETCH c1 INTO c1_rec; EXIT WHEN c1%NOTFOUND; IF c1_rec.employee_mgr = rogers_emp THEN -- If someone reported directly to Roger, we restore them but make -- them report to Roger's manager. dbms_output.put_line('Inserting employee who used to report to Roger: ' || c1_rec.employee_name); INSERT INTO my_employees VALUES (c1_rec.employee_no, c1_rec.employee_name, rogers_mgr, c1_rec.salary, c1_rec.hiredate); ELSIF c1_rec.employee_no != rogers_emp THEN -- If someone didn't report directly to Roger, we restore them with the same -- manager as before. dbms_output.put_line('Inserting employee who didn''t report directly to Roger: ' || c1_rec.employee_name); INSERT INTO my_employees VALUES (c1_rec.employee_no, c1_rec.employee_name, c1_rec.employee_mgr, c1_rec.salary, c1_rec.hiredate); END IF; END LOOP; END; / -- Now show that Roger's org is back. SELECT lpad(' ', 2*(level-1)) || employee_name "Restored Org Chart" FROM my_employees CONNECT BY PRIOR employee_no = employee_mgr START WITH employee_no = 1 ORDER BY LEVEL;
7-52
-- advance. Go to this extra trouble whenever it is crucial to retrieve data -- from a precise point. set serveroutput on; -- Make a copy of the EMPLOYEES table without the constraints, so we -- can make arbitrary changes. DROP TABLE employees2; CREATE TABLE employees2 AS SELECT * FROM employees; COMMIT; -- Wait for slightly more than 5 minutes, because the table is so new. -- Only needed in demo situations like this. EXECUTE dbms_lock.sleep(320); SELECT count(*) FROM employees2 WHERE salary = 9000; DECLARE TYPE employee_cursor IS REF CURSOR; c employee_cursor; cvar employees%ROWTYPE; old_scn NUMBER; BEGIN COMMIT; dbms_flashback.disable; old_scn := dbms_flashback.get_system_change_number; DELETE FROM employees2 WHERE salary = 9000; COMMIT; -- Those updates and deletes were in error. We need to recover the data. -- Use the data as it existed immediately before the update and delete. OPEN c FOR 'SELECT * FROM employees2 AS OF SCN :1 WHERE salary = 9000' USING old_scn; LOOP FETCH c INTO cvar; EXIT WHEN c%NOTFOUND; dbms_output.put_line('Recovering employee: ' || cvar.last_name); INSERT INTO employees2 VALUES cvar; END LOOP; COMMIT; END; / select count(*) from employees2 where salary = 9000;
DROP TABLE employees_changed_today; CREATE TABLE employees_changed_today AS SELECT * FROM employees MINUS SELECT * FROM employees AS OF TIMESTAMP TRUNC(SYSDATE);
7-54
dbms_flashback.disable; -- Flashback to a known time. dbms_flashback.enable_at_time(SYSDATE - 1); -- Open a cursor to retrieve data from the past. OPEN c FOR 'SELECT * FROM employees WHERE employee_id < 200'; -- When flashback is disabled, the cursor continues to refer to past data, -- and we can perform DML again. dbms_flashback.disable; LOOP FETCH c INTO cvar; EXIT WHEN c%NOTFOUND; -- If the employee had a null value for commission_pct yesterday, -- then overwrite the current row, setting the value to zero. IF cvar.commission_pct IS NULL THEN cvar.commission_pct := 0; UPDATE employees SET ROW = cvar WHERE employee_id = cvar.employee_id; END IF; COMMIT; END LOOP; END; / -- After: no employee should have a null value for this column. select count(*) from employees where commission_pct is null;
You can also use an implicit cursor, although this is slightly less efcient because DBMS_FLASHBACK.DISABLE is called for each loop iteration:
-- Setup: create an empty table with the same definition as EMPLOYEES. drop table yesterdays_employees; create table yesterdays_employees as select * from employees where 1 = 0; set serveroutput on size 500000; -- Less efficient technique. To allow DML statements against the current -- table within the loop body, DISABLE must be called for each loop iteration. -- Make sure database is in a consistent state. COMMIT; -- First make sure flashback is turned off initially. EXECUTE DBMS_FLASHBACK.DISABLE; -- Then set it to a known value. EXECUTE DBMS_FLASHBACK.ENABLE_AT_TIME(SYSDATE - 1);
BEGIN -- The FOR loop is examining data values from the past. FOR c in (SELECT * FROM employees WHERE employee_id < 200) LOOP -- DISABLE gets called multiple times, but that's OK. DBMS_FLASHBACK.DISABLE; dbms_output.put_line('Inserting employee #' || c.employee_id); -- Because flashback is disabled within the loop body, we can access the -- present state of the data, and issue DML statements to undo the changes -- or store the old data somewhere else. INSERT INTO yesterdays_employees VALUES c; END LOOP; END; / -- After the loop, once more make sure flashback is turned off. EXECUTE DBMS_FLASHBACK.DISABLE; select count(*) from yesterdays_employees;
7-56
8
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, exible 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:
s
Native dynamic SQL, where you place dynamic SQL statements directly into PL/SQL blocks. Calling procedures in the DBMS_SQL package.
"What Is Dynamic SQL?" on page 8-2 "Why Use Dynamic SQL?" on page 8-3 "A Dynamic SQL Scenario Using Native Dynamic SQL" on page 8-8 "Choosing Between Native Dynamic SQL and the DBMS_SQL Package" on page 8-11 "Using Dynamic SQL in Languages Other Than PL/SQL" on page 8-21 "Using PL/SQL Records in SQL INSERT and UPDATE Statements" on page 8-21
You can nd details about the DBMS_SQL package in the Oracle9i Supplied PL/SQL Packages and Types Reference.
Successful compilation veries that the SQL statements reference valid database objects. Successful compilation veries 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 denes 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 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 specied ORDER BY clause. Dynamic SQL programs can handle changes in data denitions, without the need to recompile. This makes dynamic SQL much more exible 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 denition language (DDL) statements and other SQL statements that are not supported in purely static SQL programs.
8-2
Data denition 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) 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; /
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 denitions of tables are constantly changing Applications that query a database where new tables are created often
For examples, see "Querying Using Dynamic SQL: Example" on page 8-17, and see the query examples in "A Dynamic SQL Scenario Using Native Dynamic SQL" on page 8-8.
8-4
query_str VARCHAR2(200); 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; /
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.
8-6
Using native dynamic SQL, you can write a smaller, more exible event dispatcher similar to the following:
CREATE OR REPLACE PROCEDURE event_dispatcher (event NUMBER, param NUMBER) IS BEGIN EXECUTE IMMEDIATE 'BEGIN EVENT_HANDLER_' || to_char(event) || '(:1); END;' USING param; END; /
Execute DDL and DML operations Execute single row and multiple row queries
The database in this scenario is a companys 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 denition:
Column Name LOCATION Null? NOT_NULL Type VARCHAR2(200)
Multiple emp_location tables contain the employee information, where location is the name of city where the ofce is located. For example, a table named emp_houston contains employee information for the companys Houston ofce, while a table named emp_boston contains employee information for the companys Boston ofce. Each emp_location table has the following denition:
Column Name EMPNO ENAME JOB SAL DEPTNO Null? NOT_NULL NOT_NULL NOT_NULL NOT_NULL NOT_NULL Type NUMBER(4) VARCHAR2(10) VARCHAR2(9) NUMBER(7,2) NUMBER(2)
The following sections describe various native dynamic SQL operations that can be performed on the data in the hr database.
8-8
/ SHOW ERRORS;
8-10
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. The following sections provide detailed information about the advantages of both methods.
See Also: The PL/SQL Users 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 Users Guide and Reference, native dynamic SQL is referred to simply as dynamic SQL.
8-12
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) IS BEGIN EXECUTE IMMEDIATE DELETE FROM dept WHERE deptno = :1 USING my_deptno; END; / SHOW ERRORS;
8-14
Here, the same cursor is reused for different values of the bind my_deptno, improving performance and scalabilty.
arrays. See the Oracle9i Supplied PL/SQL Packages and Types Reference for information.
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" on page 8-20 for examples of DBMS_SQL package code and native dynamic SQL code that uses a RETURNING clause.
8-16
extra prepare operations incur a small performance penalty, the slowdown is typically outweighed by the performance benets of native dynamic SQL.
In general, the native dynamic SQL code is more readable and compact, which can improve developer productivity.
This example queries for employees with the job description SALESMAN in the job column of the emp table. Table 82 shows sample code that accomplishes this query using the DBMS_SQL package and native dynamic SQL.
Table 82 Querying Using the DBMS_SQL Package and Native Dynamic SQL
8-18
This example inserts a new row for which the column values are in the PL/SQL variables deptnumber, deptname, and location. Table 83 shows sample code that accomplishes this DML operation using the DBMS_SQL package and native dynamic SQL.
Table 83 DML Operation Using the DBMS_SQL Package and Native Dynamic SQL
DBMS_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); -- close END; /
Table 84 shows sample code that accomplishes this operation using both the DBMS_SQL package and native dynamic SQL.
Table 84 DML Returning Operation Using the DBMS_SQL Package and Native Dynamic SQL
DBMS_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); dbms_sql.close_cursor(cur_hdl); END; /
8-20
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
Oracle Call Interface Programmers Guide Pro*C/C++ Precompiler Programmers Guide Pro*COBOL Precompiler Programmers Guide Oracle9i Java Stored Procedures Developers Guide
-- 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.
See Also: PL/SQL Users Guide and Reference, for more information
8-22
9
Using Procedures and Packages
This chapter describes some of the procedural capabilities of Oracle for application development, including:
s
Overview of PL/SQL Program Units Hiding PL/SQL Code with the PL/SQL Wrapper Remote Dependencies Cursor Variables Handling PL/SQL Compile-Time Errors Handling Run-Time PL/SQL Errors Debugging Stored Procedures Calling Stored Procedures Calling Remote Procedures Calling Stored Functions from SQL Expressions Returning Large Amounts of Data from a Function Coding Your Own Aggregate Functions
engine that lets you run PL/SQL locally. You can even use PL/SQL for some database applications in place of 3GL programs that use embedded SQL or the Oracle Call Interface (OCI). PL/SQL program units include:
s
Anonymous Blocks Stored Program Units (Procedures, Functions, and Packages) Triggers
See Also,: PL/SQL Users Guide and Reference. for syntax and
examples of operations on PL/SQL packages. Oracle9i Supplied PL/SQL Packages and Types Reference. for information about the PL/SQL packages that come with the Oracle database server.
Anonymous Blocks
An anonymous block is a PL/SQL program unit that has no name and it does not require the explicit presence of the BEGIN and END keywords to enclose the executable statements. An anonymous block consists of an optional declarative part, an executable part, and one or more optional exception handlers.
9-2
The declarative part declares PL/SQL variables, exceptions, and cursors. The executable part contains PL/SQL code and SQL statements, and can contain nested blocks. Exception handlers contain code that is called when the exception is raised, either as a predened PL/SQL exception (such as NO_DATA_FOUND or ZERO_DIVIDE) or as an exception that you dene. The following short example of a PL/SQL anonymous block prints the names of all employees in department 20 in the Emp_tab table, using the DBMS_OUTPUT package:
DECLARE Emp_name Cursor VARCHAR2(10); c1 IS SELECT Ename FROM Emp_tab WHERE Deptno = 20;
BEGIN OPEN c1; LOOP FETCH c1 INTO Emp_name; EXIT WHEN c1%NOTFOUND; DBMS_OUTPUT.PUT_LINE(Emp_name); END LOOP; END;
Note: If you test this block using SQL*Plus, then enter the
statement SET SERVEROUTPUT ON, so that output using the DBMS_OUTPUT procedures (for example, PUT_LINE) is activated. Also, end the example with a slash (/) to activate it.
package, see Oracle9i Supplied PL/SQL Packages and Types Reference. Exceptions let you handle Oracle error conditions within PL/SQL program logic. This allows your application to prevent the server from issuing an error that could cause the client application to abend. The following anonymous block handles the predened Oracle exception NO_DATA_FOUND (which would result in an ORA-01403 error if not handled):
DECLARE Emp_number INTEGER := 9999; Emp_name VARCHAR2(10); BEGIN SELECT Ename INTO Emp_name FROM Emp_tab WHERE Empno = Emp_number; -- no such number DBMS_OUTPUT.PUT_LINE(Employee name is || Emp_name); EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE(No such employee: || Emp_number); END;
You can also dene your own exceptions, declare them in the declaration part of a block, and dene them in the exception part of the block. An example follows:
DECLARE Emp_name VARCHAR2(10); Emp_number INTEGER; Empno_out_of_range EXCEPTION; BEGIN Emp_number := 10001; IF Emp_number > 9999 OR Emp_number < 1000 THEN RAISE Empno_out_of_range; ELSE SELECT Ename INTO Emp_name FROM Emp_tab WHERE Empno = Emp_number; DBMS_OUTPUT.PUT_LINE(Employee name is || Emp_name); END IF; EXCEPTION WHEN Empno_out_of_range THEN DBMS_OUTPUT.PUT_LINE(Employee number || Emp_number || is out of range.); END;
see the PL/SQL Users Guide and Reference. Anonymous blocks are usually used interactively from a tool, such as SQL*Plus, or in a precompiler, OCI, or SQL*Module application. They are usually used to call stored procedures or to open cursor variables.
See Also: "Cursor Variables" on page 9-31.
9-4
Has a name. Can take parameters, and can return values. Is stored in the data dictionary. Can be called by many users.
Note: The term stored procedure is sometimes used generically
for both stored procedures and stored functions. The only difference between procedures and functions is that functions always return a single value to the caller, while procedures do not return a value to the caller.
by SQL*Module, then the stored procedure name must also be a legal identier in the calling host 3GL language, such as Ada or C.
PROCEDURE...
PROCEDURE Get_emp_names (Dept_num IN NUMBER) IS Emp_name VARCHAR2(10); CURSOR c1 (Depno NUMBER) IS SELECT Ename FROM Emp_tab WHERE deptno = Depno; BEGIN OPEN c1(Dept_num); LOOP FETCH c1 INTO Emp_name; EXIT WHEN C1%NOTFOUND; DBMS_OUTPUT.PUT_LINE(Emp_name); END LOOP; CLOSE c1; END;
In this stored procedure example, the department number is an input parameter which is used when the parameterized cursor c1 is opened. The formal parameters of a procedure have three major attributes:
Parameter Attribute Description
Name Mode
This must be a legal PL/SQL identier. This indicates whether the parameter is an input-only parameter (IN), an output-only parameter (OUT), or is both an input and an output parameter (IN OUT). If the mode is not specied, then IN is assumed. This is a standard PL/SQL datatype.
Datatype
Parameter Modes Parameter modes dene the behavior of formal parameters. The three parameter modes, IN (the default), OUT, and IN OUT, can be used with any subprogram. However, avoid using the OUT and IN OUT modes with functions. The purpose of a function is to take no arguments and return a single value. It is poor programming practice to have a function return multiple values. Also, functions should be free from side effects, which change the values of variables not local to the subprogram. Table 91 summarizes the information about parameter modes.
9-6
Returns values to the caller. Passes initial values to a subprogram; returns updated values to the caller. Formal parameter acts like an uninitialized variable. Formal parameter cannot be used in an expression; must be assigned a value. Actual parameter must be a variable. Formal parameter acts like an initialized variable. Formal parameter should be assigned a value. Actual parameter must be a variable.
Formal parameter acts like a constant. Formal parameter cannot be assigned a value. Actual parameter can be a constant, initialized variable, literal, or expression.
Parameter Datatypes The datatype of a formal parameter consists of one of the following:
s
An unconstrained type name, such as NUMBER or VARCHAR2. A type that is constrained using the %TYPE or %ROWTYPE attributes.
Note: Numerically constrained types such as NUMBER(2) or
VARCHAR2(20) are not allowed in a parameter list. %TYPE and %ROWTYPE Attributes Use the type attributes %TYPE and %ROWTYPE to constrain the parameter. For example, the Get_emp_names procedure specication in "Parameters for Procedures and Functions" on page 9-5 could be written as the following:
PROCEDURE Get_emp_names(Dept_num IN Emp_tab.Deptno%TYPE)
This has the Dept_num parameter take the same datatype as the Deptno column in the Emp_tab table. The column and table must be available when a declaration using %TYPE (or %ROWTYPE) is elaborated. Using %TYPE is recommended, because if the type of the column in the table changes, then it is not necessary to change the application code. If the Get_emp_names procedure is part of a package, then you can use previously-declared public (package) variables to constrain a parameter datatype. For example:
Dept_number number(2); ... PROCEDURE Get_emp_names(Dept_num IN Dept_number%TYPE);
Use the %ROWTYPE attribute to create a record that contains all the columns of the specied table. The following example denes the Get_emp_rec procedure, which returns all the columns of the Emp_tab table in a PL/SQL record for the given empno:
Caution: To execute the following, use CREATE OR REPLACE
PROCEDURE...
PROCEDURE Get_emp_rec (Emp_number IN Emp_tab.Empno%TYPE, Emp_ret OUT Emp_tab%ROWTYPE) IS BEGIN SELECT Empno, Ename, Job, Mgr, Hiredate, Sal, Comm, Deptno INTO Emp_ret FROM Emp_tab WHERE Empno = Emp_number; END;
9-8
END;
Stored functions can also return values that are declared using %ROWTYPE. For example:
FUNCTION Get_emp_rec (Dept_num IN Emp_tab.Deptno%TYPE) RETURN Emp_tab%ROWTYPE IS ...
Tables and Records You can pass PL/SQL tables as parameters to stored procedures and functions. You can also pass tables of records as parameters.
Note: When passing a user dened type, such as a PL/SQL table
or record to a remote procedure, to make PL/SQL use the same denition so that the type checker can verify the source, you must create a redundant loop back DBLINK so that when the PL/SQL compiles, both sources pull from the same location. Default Parameter Values Parameters can take default values. Use the DEFAULT keyword or the assignment operator to give a parameter a default value. For example, the specication for the Get_emp_names procedure could be written as the following:
PROCEDURE Get_emp_names (Dept_num IN NUMBER DEFAULT 20) IS ...
or
PROCEDURE Get_emp_names (Dept_num IN NUMBER := 20) IS ...
When a parameter takes a default value, it can be omitted from the actual parameter list when you call the procedure. When you do specify the parameter value on the call, it overrides the default value.
Note: Unlike in an anonymous PL/SQL block, you do not use the
keyword DECLARE before the declarations of variables, cursors, and exceptions in a stored procedure. In fact, it is an error to use it.
For example, to use the example in "%TYPE and %ROWTYPE Attributes" on page 9-7, create a text (source) le called get_emp.sql containing the following code:
CREATE PROCEDURE Get_emp_rec (Emp_number IN Emp_tab.Empno%TYPE, Emp_ret OUT Emp_tab%ROWTYPE) AS BEGIN SELECT Empno, Ename, Job, Mgr, Hiredate, Sal, Comm, Deptno INTO Emp_ret FROM Emp_tab WHERE Empno = Emp_number; END; /
Then, using an interactive tool such as SQL*Plus, load the text le containing the procedure by entering the following statement:
SQL> @get_emp
This loads the procedure into the current schema from the get_emp.sql le (.sql is the default le extension). Note the slash (/) at the end of the code. This is not part of the code; it just activates the loading of the procedure. Use the CREATE [OR REPLACE] FUNCTION... statement to store functions.
Caution: When developing a new procedure, it is usually much
more convenient to use the CREATE OR REPLACE PROCEDURE statement. This replaces any previous version of that procedure in the same schema with the newer version, but note that this is done without warning. You can use either the keyword IS or AS after the procedure parameter list.
See Also: Oracle9i Database Reference for the complete syntax of
the CREATE PROCEDURE and CREATE FUNCTION statements. Privileges to Create Procedures and Functions To create a standalone procedure or function, or package specication or body, you must meet the following prerequisites:
9-10
You must have the CREATE PROCEDURE system privilege to create a procedure or package in your schema, or the CREATE ANY PROCEDURE system privilege to create a procedure or package in another users schema.
Note: To create without errors (to compile the procedure or
The owner of the procedure or package must be explicitly granted the necessary object privileges for all objects referenced within the body of the code. The owner cannot obtain required privileges through roles.
If the privileges of a procedures or a packages owner change, then the procedure must be reauthenticated before it is run. If a necessary privilege to a referenced object is revoked from the owner of the procedure or package, then the procedure cannot be run. The EXECUTE privilege on a procedure gives a user the right to run a procedure owned by another user. Privileged users run the procedure under the security domain of the procedures owner. Therefore, users never need to be granted the privileges to the objects referenced by a procedure. This allows for more disciplined and efcient security strategies with database applications and their users. Furthermore, all procedures and packages are stored in the data dictionary (in the SYSTEM tablespace). No quota controls the amount of space available to a user who creates procedures and packages.
Note: Package creation requires a sort. So the user creating the
package should be able to create a sort segment in the temporary tablespace with which the user is associated.
page 9-46.
warning.
The parameters can apply to procedures, functions, packages, types, and triggers. Once specied, the settings apply whenever these schema objects are updated by CREATE OR REPLACE or the automatic recompilation that happens when the object is invalidated. When a schema object is dropped, any settings that apply to only that object are lost. You can nd out what settings are in effect by querying the catalog views ALL_PLSQL_SWITCH_SETTINGS and USER_PLSQL_SWITCH_SETTINGS. You can nd out all the possible setting names and parameters by querying the view ALL_PLSQL_SWITCHES. Within an application, you can also nd this information by calling functions in the DBMS_DESCRIBE package.
Privileges to Drop Procedures and Functions To drop a procedure, function, or package, the procedure or package must be in your schema, or you must have the DROP ANY PROCEDURE privilege. An individual procedure within a package cannot be dropped; the containing package specication and body must be re-created without the procedures to be dropped.
9-12
External Procedures
A PL/SQL procedure executing on an Oracle Server can call an external procedure written in a 3GL. The 3GL procedure runs in a separate address space from that of the Oracle Server.
See Also: For information about external procedures, see the
PL/SQL Packages
A package is an encapsulated collection of related program objects (for example, procedures, functions, variables, constants, cursors, and exceptions) stored together in the database. Using packages is an alternative to creating procedures and functions as standalone schema objects. Packages have many advantages over standalone procedures and functions. For example, they:
s
Let you organize your application development more efciently. Let you grant privileges more efciently. Let you modify package objects without recompiling dependent schema objects. Enable Oracle to read multiple package objects into memory at once. Can contain global variables and cursors that are available to all procedures and functions in the package. Let you overload procedures or functions. Overloading a procedure means creating multiple procedures with the same name in the same package, each taking arguments of different number or datatype.
See Also: The PL/SQL Users Guide and Reference has more
information about subprogram name overloading. The specication part of a package declares the public types, variables, constants, and subprograms that are visible outside the immediate scope of the package. The body of a package denes the objects declared in the specication, as well as private objects that are not visible to applications outside the package. Example of a PL/SQL Package Specication and Body The following example shows a package specication for a package named Employee_management. The package contains one stored function and two stored procedures. The body for this package denes the function and the procedures:
CREATE PACKAGE BODY Employee_management AS FUNCTION Hire_emp (Name VARCHAR2, Job VARCHAR2, Mgr NUMBER, Hiredate DATE, Sal NUMBER, Comm NUMBER, Deptno NUMBER) RETURN NUMBER IS New_empno NUMBER(10); -----This function accepts all arguments for the fields in the employee table except for the employee number. A value for this field is supplied by a sequence. The function returns the sequence number generated by the call to this function. BEGIN SELECT Emp_sequence.NEXTVAL INTO New_empno FROM dual; INSERT INTO Emp_tab VALUES (New_empno, Name, Job, Mgr, Hiredate, Sal, Comm, Deptno); RETURN (New_empno); END Hire_emp; PROCEDURE fire_emp(emp_id IN NUMBER) AS -- This procedure deletes the employee with an employee -- number that corresponds to the argument Emp_id. If -- no employee is found, then an exception is raised. BEGIN DELETE FROM Emp_tab WHERE Empno = Emp_id; IF SQL%NOTFOUND THEN Raise_application_error(-20011, Invalid Employee Number: || TO_CHAR(Emp_id)); END IF; END fire_emp; PROCEDURE Sal_raise (Emp_id IN NUMBER, Sal_incr IN NUMBER) AS -----This procedure accepts two arguments. Emp_id is a number that corresponds to an employee number. SAL_INCR is the amount by which to increase the employees salary. If employee exists, then update salary with increase. BEGIN UPDATE Emp_tab SET Sal = Sal + Sal_incr WHERE Empno = Emp_id;
9-14
IF SQL%NOTFOUND THEN Raise_application_error(-20011, Invalid Employee Number: || TO_CHAR(Emp_id)); END IF; END Sal_raise; END Employee_management;
Note: If you want to try this example, then rst create the
Creating Packages
Each part of a package is created with a different statement. Create the package specication using the CREATE PACKAGE statement. The CREATE PACKAGE statement declares public package objects. To create a package body, use the CREATE PACKAGE BODY statement. The CREATE PACKAGE BODY statement denes the procedural code of the public procedures and functions declared in the package specication. You can also dene private, or local, package procedures, functions, and variables in a package body. These objects can only be accessed by other procedures and functions in the body of the same package. They are not visible to external users, regardless of the privileges they hold.
It is often more convenient to add the OR REPLACE clause in the CREATE PACKAGE or CREATE PACKAGE BODY statements when you are rst developing your application. The effect of this option is to drop the package or the package body without warning. The CREATE statements would then be the following:
CREATE OR REPLACE PACKAGE Package_name AS ...
and
CREATE OR REPLACE PACKAGE BODY Package_name AS ...
Procedures and functions declared in the package specication. Denitions of cursors declared in the package specication. Local procedures and functions, not declared in the package specication. Local variables.
Procedures, functions, cursors, and variables that are declared in the package specication are global. They can be called, or used, by external users that have EXECUTE permission for the package or that have EXECUTE ANY PROCEDURE privileges. When you create the package body, make sure that each procedure that you dene in the body has the same parameters, by name, datatype, and mode, as the declaration in the package specication. For functions in the package body, the parameters and the return type must agree in name and type. Privileges to Create or Drop Packages The privileges required to create or drop a package specication or package body are the same as those required to create or drop a standalone procedure or function.
See Also: "Privileges to Create Procedures and Functions" on
page 9-10 and "Privileges to Drop Procedures and Functions" on page 9-12.
9-16
The second time a session makes such a package call, the package is reinstantiated for the session without error.
Note: Oracle has been optimized to not return this message to the
session calling the package that it invalidated. Thus, in the previous example, session S receives this message the rst time it calls package P2, but it does not receive it when calling P1. In most production environments, DDL operations that can cause invalidations are usually performed during inactive working hours; therefore, this situation might not be a problem for end-user applications. However, if package specication or body invalidations are common in your system during working hours, then you might want to code your applications to detect for this error when package calls are made.
Oracle-Supplied Packages
There are many built-in packages provided with the Oracle database, either to extend the functionality of the database or to give PL/SQL access to SQL features. You can call these packages from your application. These packages run as the calling user, rather than the package owner. Unless otherwise noted, the packages are callable through public synonyms of the same name. For details on all of these Oracle-supplied packages, see:
Oracle9i Supplied PL/SQL Packages and Types Reference. Many of these packages are used only in very specic situations. Some of the more general-purpose ones are DBMS_JOB, DBMS_LOB, DBMS_LOCK, DBMS_OUTPUT, DBMS_RANDOM, DBMS_SQL, DBMS_UTILITY, DBMS_XMLGEN, UTL_FILE, UTL_HTTP, and UTL_SMTP, . Oracle Spatial Users Guide and Reference Oracle Time Series Users Guide
Binding is the assignment of values to PL/SQL variables in SQL statements. Bulk binding is binding an entire collection at once. Bulk binds pass the entire collection back and forth between the two engines in a single operation. Typically, using bulk binds improves performance for SQL statements that affect four or more database rows. The more rows affected by a SQL statement, the greater the performance gain from bulk binds.
9-18
decide if you should use them in your PL/SQL applications. For detailed information about using bulk binds, including ways to handle exceptions that occur in the middle of a bulk bind operation, see the PL/SQL Users Guide and Reference.
Without the bulk bind, PL/SQL sends a SQL statement to the SQL engine for each employee that is updated, leading to context switches that hurt performance. If you have a set of rows prepared in a PL/SQL table, you can bulk-insert or bulk-update the data using a loop like:
FORALL i in Emp_Data.FIRST..Emp_Data.LAST INSERT INTO Emp_tab VALUES(Emp_Data(i));
SELECT Statements that Reference Collections The BULK COLLECT INTO clause can improve the performance of queries that reference collections. For example, the following PL/SQL block queries multiple values into PL/SQL tables, both with and without bulk binds:
-- Find all employees whose managers ID number is 7698. DECLARE TYPE Var_tab IS TABLE OF VARCHAR2(20) INDEX BY BINARY_INTEGER; Empno VAR_TAB; Ename VAR_TAB; Counter NUMBER; CURSOR C IS SELECT Empno, Ename FROM Emp_tab WHERE Mgr = 7698; BEGIN -- Efficient method, using a bulk bind SELECT Empno, Ename BULK COLLECT INTO Empno, Ename FROM Emp_Tab WHERE Mgr = 7698; -- Slower method, assigning each collection element within a loop. counter := 1; FOR rec IN C LOOP Empno(Counter) := rec.Empno; Ename(Counter) := rec.Ename; Counter := Counter + 1; END LOOP; END;
You can use BULK COLLECT INTO with tables of scalar values, or tables of %TYPE values. Without the bulk bind, PL/SQL sends a SQL statement to the SQL engine for each employee that is selected, leading to context switches that hurt performance. FOR Loops that Reference Collections and the Returning Into Clause You can use the FORALL keyword along with the BULK COLLECT INTO keywords to improve the performance of FOR loops that reference collections and return DML. For example, the following PL/SQL block updates the EMP_TAB table by computing bonuses for a collection of employees; then it returns the bonuses in a column called Bonlist. The actions are performed both with and without using bulk binds:
9-20
DECLARE TYPE Emplist IS VARRAY(100) OF NUMBER; Empids EMPLIST := EMPLIST(7369, 7499, 7521, 7566, 7654, 7698); TYPE Bonlist IS TABLE OF Emp_tab.sal%TYPE; Bonlist_inst BONLIST; BEGIN Bonlist_inst := BONLIST(1,2,3,4,5); FORALL i IN Empids.FIRST..empIDs.LAST UPDATE Emp_tab SET Bonus = 0.1 * Sal WHERE Empno = Empids(i) RETURNING Sal BULK COLLECT INTO Bonlist; FOR i IN Empids.FIRST..Empids.LAST LOOP UPDATE Emp_tab Set Bonus = 0.1 * sal WHERE Empno = Empids(i) RETURNING Sal INTO BONLIST(i); END LOOP; END;
Without the bulk bind, PL/SQL sends a SQL statement to the SQL engine for each employee that is updated, leading to context switches that hurt performance.
Triggers
A trigger is a special kind of PL/SQL anonymous block. You can dene triggers to re before or after SQL statements, either on a statement level or for each row that is affected. You can also dene INSTEAD OF triggers or system triggers (triggers on DATABASE and SCHEMA).
See Also: Chapter 15, "Using Triggers".
Tuning chapter of the PL/SQL Users Guide and Reference. For full details on Java native compilation, see the Oracle9i Java Developers Guide.
Remote Dependencies
Dependencies among PL/SQL program units can be handled in two ways:
s
Timestamps Signatures
Timestamps
If timestamps are used to handle dependencies among PL/SQL program units, then whenever you alter a program unit or a relevant schema object, all of its dependent units are marked as invalid and must be recompiled before they can be run. Each program unit carries a timestamp that is set by the server when the unit is created or recompiled. Figure 91 demonstrates this graphically. Procedures P1 and P2 call stored procedure P3. Stored procedure P3 references table T1. In this
9-22
Remote Dependencies
example, each of the procedures is dependent on table T1. P3 depends upon T1 directly, while P1 and P2 depend upon T1 indirectly.
Figure 91 Dependency Relationships
P1
P3
T1
P2
If P3 is altered, then P1 and P2 are marked as invalid immediately, if they are on the same server as P3. The compiled states of P1 and P2 contain records of the timestamp of P3. Therefore, if the procedure P3 is altered and recompiled, then the timestamp on P3 no longer matches the value that was recorded for P3 during the compilation of P1 and P2. If P1 and P2 are on a client system, or on another Oracle Server in a distributed environment, then the timestamp information is used to mark them as invalid at runtime.
Remote Dependencies
application from running at all. The client application developer must then redistribute new versions of the application to all customers.
Signatures
To alleviate some of the problems with the timestamp-only dependency model, Oracle provides the additional capability of remote dependencies using signatures. The signature capability affects only remote dependencies. Local (same server) dependencies are not affected, as recompilation is always possible in this environment. A signature is associated with each compiled stored program unit. It identies the unit using the following criteria:
s
The name of the unit (the package, procedure, or function name). The types of each of the parameters of the subprogram. The modes of the parameters (IN, OUT, IN OUT). The number of parameters. The type of the return value for a function.
The user has control over whether signatures or timestamps govern remote dependencies.
See Also: "Controlling Remote Dependencies" on page 9-29.
When the signature dependency model is used, a dependency on a remote program unit causes an invalidation of the dependent unit if the dependent unit contains a call to a subprogram in the parent unit, and if the signature of this subprogram has been changed in an incompatible manner. For example, consider a procedure get_emp_name stored on a server in Boston (BOSTON_SERVER). The procedure is dened as the following:
Note: You may need to set up data structures, similar to the
9-24
Remote Dependencies
emp_number IN NUMBER, hire_date OUT VARCHAR2, emp_name OUT VARCHAR2) AS BEGIN SELECT ename, to_char(hiredate, DD-MON-YY) INTO emp_name, hire_date FROM emp WHERE empno = emp_number; END;
When get_emp_name is compiled on BOSTON_SERVER, its signature, as well as its timestamp, is recorded. Now, assume that on another server in California, some PL/SQL code calls get_emp_name identifying it using a DBlink called BOSTON_SERVER, as follows:
CREATE OR REPLACE PROCEDURE print_ename (emp_number IN NUMBER) AS hire_date VARCHAR2(12); ename VARCHAR2(10); BEGIN get_emp_name@BOSTON_SERVER(emp_number, hire_date, ename); dbms_output.put_line(ename); dbms_output.put_line(hire_date); END;
When this California server code is compiled, the following actions take place:
s
A connection is made to the Boston server. The signature of get_emp_name is transferred to the California server. The signature is recorded in the compiled state of print_ename.
At runtime, during the remote procedure call from the California server to the Boston server, the recorded signature of get_emp_name that was saved in the compiled state of print_ename gets sent to the Boston server, regardless of whether or not there were any changes. If the timestamp dependency mode is in effect, then a mismatch in timestamps causes an error status to be returned to the calling procedure. However, if the signature mode is in effect, then any mismatch in timestamps is ignored, and the recorded signature of get_emp_name in the compiled state of Print_ename on the California server is compared with the current signature of get_emp_name on the Boston server. If they match, then the call succeeds. If they do not match, then an error status is returned to the print_name procedure.
Remote Dependencies
Note that the get_emp_name procedure on the Boston server could have been changed. Or, its timestamp could be different from that recorded in the print_name procedure on the California server, possibly due to the installation of a new release of the server. As long as the signature remote dependency mode is in effect on the California server, a timestamp mismatch does not cause an error when get_emp_name is called.
Note: DETERMINISTIC, PARALLEL_ENABLE, and purity information do not show in the signature mode. Optimizations based on these settings are not automatically reconsidered if a function on a remote system is redened with different settings. This may lead to incorrect query results when calls to the remote function occur, even indirectly, in a SQL statement, or if the remote function is used, even indirectly, in a function-based index.
9-26
Remote Dependencies
Modes Changing to or from an explicit specication of the default parameter mode IN does not change the signature of a subprogram. For example, changing between:
PROCEDURE P1 (Param1 NUMBER); PROCEDURE P1 (Param1 IN NUMBER);
does not change the signature. Any other change of parameter mode does change the signature. Default Parameter Values Changing the specication of a default parameter value does not change the signature. For example, procedure P1 has the same signature in the following two examples:
PROCEDURE P1 (Param1 IN NUMBER := 100); PROCEDURE P1 (Param1 IN NUMBER := 200);
An application developer who requires that callers get the new default value must recompile the called procedure, but no signature-based invalidation occurs when a default parameter value assignment is changed.
The specication of the procedure has not changed, so its signature has not changed. But if the procedure specication is changed to the following:
CREATE OR REPLACE PROCEDURE Get_emp_name ( Emp_number IN NUMBER, Hire_date OUT DATE, Emp_name OUT VARCHAR2) AS
Remote Dependencies
And if the body is changed accordingly, then the signature changes, because the parameter Hire_date has a different datatype. However, if the name of that parameter changes to When_hired, and the datatype remains VARCHAR2, and the mode remains OUT, the signature does not change. Changing the name of a formal parameter does not change the signature of the unit. Consider the following example:
CREATE OR REPLACE PACKAGE Emp_package AS TYPE Emp_data_type IS RECORD ( Emp_number NUMBER, Hire_date VARCHAR2(12), Emp_name VARCHAR2(10)); PROCEDURE Get_emp_data (Emp_data IN OUT Emp_data_type); END; CREATE OR REPLACE PACKAGE BODY Emp_package AS PROCEDURE Get_emp_data (Emp_data IN OUT Emp_data_type) IS BEGIN SELECT Empno, Ename, TO_CHAR(Hiredate, DD/MON/YY) INTO Emp_data FROM Emp_tab WHERE Empno = Emp_data.Emp_number; END; END;
If the package specication is changed so that the records eld names are changed, but the types remain the same, then this does not affect the signature. For example, the following package specication has the same signature as the previous package specication example:
CREATE OR REPLACE PACKAGE Emp_package AS TYPE Emp_data_type IS RECORD ( Emp_num NUMBER, -- was Emp_number Hire_dat VARCHAR2(12), -- was Hire_date Empname VARCHAR2(10)); -- was Emp_name PROCEDURE Get_emp_data (Emp_data IN OUT Emp_data_type); END;
Changing the name of the type of a parameter does not cause a change in the signature if the type remains the same as before. For example, the following package specication for Emp_package is the same as the rst one:
9-28
Remote Dependencies
CREATE OR REPLACE PACKAGE Emp_package AS TYPE Emp_data_record_type IS RECORD ( Emp_number NUMBER, Hire_date VARCHAR2(12), Emp_name VARCHAR2(10)); PROCEDURE Get_emp_data (Emp_data IN OUT Emp_data_record_type); END;
Then only timestamps are used to resolve dependencies (if this is not explicitly overridden dynamically).
s
Then signatures are used to resolve dependencies (if this not explicitly overridden dynamically).
s
You can alter the mode dynamically by using the DDL statements. For example, this example alters the dependency model for the current session:
ALTER SESSION SET REMOTE_DEPENDENCIES_MODE = {SIGNATURE | TIMESTAMP}
If the REMOTE_DEPENDENCIES_MODE parameter is not specied, either in the init.ora parameter le or using the ALTER SESSION or ALTER SYSTEM DDL statements, then timestamp is the default value. Therefore, unless you explicitly use the REMOTE_DEPENDENCIES_MODE parameter, or the appropriate DDL statement, your server is operating using the timestamp dependency model. When you use REMOTE_DEPENDENCIES_MODE=SIGNATURE:
Remote Dependencies
If you change the default value of a parameter of a remote procedure, then the local procedure calling the remote procedure is not invalidated. If the call to the remote procedure does not supply the parameter, then the default value is used. In this case, because invalidation/recompilation does not automatically occur, the old default value is used. If you want to see the new default values, then you must recompile the calling procedure manually. If you add a new overloaded procedure in a package (a new procedure with the same name as an existing one), then local procedures that call the remote procedure are not invalidated. If it turns out that this overloading results in a rebinding of existing calls from the local procedure under the timestamp mode, then this rebinding does not happen under the signature mode, because the local procedure does not get invalidated. You must recompile the local procedure manually to achieve the new rebinding. If the types of parameters of an existing packaged procedure are changed so that the new types have the same shape as the old ones, then the local calling procedure is not invalidated or recompiled automatically. You must recompile the calling procedure manually to get the semantics of the new type.
Dependency Resolution
When REMOTE_DEPENDENCIES_MODE = TIMESTAMP (the default value), dependencies among program units are handled by comparing timestamps at runtime. If the timestamp of a called remote procedure does not match the timestamp of the called procedure, then the calling (dependent) unit is invalidated and must be recompiled. In this case, if there is no local PL/SQL compiler, then the calling application cannot proceed. In the timestamp dependency mode, signatures are not compared. If there is a local PL/SQL compiler, then recompilation happens automatically when the calling procedure is run. When REMOTE_DEPENDENCIES_MODE = SIGNATURE, the recorded timestamp in the calling unit is rst compared to the current timestamp in the called remote unit. If they match, then the call proceeds. If the timestamps do not match, then the signature of the called remote subprogram, as recorded in the calling subprogram, is compared with the current signature of the called subprogram. If they do not match (using the criteria described in the section "When Does a Signature Change?" on page 9-26), then an error is returned to the calling session.
9-30
Cursor Variables
Server-side PL/SQL users can set the parameter to TIMESTAMP (or let it default to that) to get the timestamp dependency mode. Server-side PL/SQL users can choose to use the signature dependency mode if they have a distributed system and they want to avoid possible unnecessary recompilations. Client-side PL/SQL users should set the parameter to SIGNATURE. This allows: Installation of new applications at client sites, without the need to recompile procedures. Ability to upgrade the server, without encountering timestamp mismatches.
When using signature mode on the server side, add new procedures to the end of the procedure (or function) declarations in a package specication. Adding a new procedure in the middle of the list of declarations can cause unnecessary invalidation and recompilation of dependent procedures.
Cursor Variables
A cursor is a static object; a cursor variable is a pointer to a cursor. Because cursor variables are pointers, they can be passed and returned as parameters to procedures and functions. A cursor variable can also refer to different cursors in its lifetime. Some additional advantages of cursor variables include:
s
Encapsulation Queries are centralized in the stored procedure that opens the cursor variable. Ease of maintenance If you need to change the cursor, then you only need to make the change in one place: the stored procedure. There is no need to change each application. Convenient security The user of the application is the username used when the application connects to the server. The user must have EXECUTE permission on the stored procedure that opens the cursor. But, the user does not need to have READ permission on the tables used in the query. This capability can be used to limit access to the columns in the table, as well as access to other stored procedures.
Cursor Variables
See Also: The PL/SQL Users Guide and Reference has a complete
Pro*C/C++ Precompiler Programmers Guide Pro*COBOL Precompiler Programmers Guide Oracle Call Interface Programmers Guide SQL*Module for Ada Programmers Guide
Fetching Data
The following package denes a PL/SQL cursor variable type Emp_val_cv_type, and two procedures. The rst procedure, Open_emp_cv, opens the cursor variable using a bind variable in the WHERE clause. The second procedure, Fetch_emp_data, fetches rows from the Emp_tab table using the cursor variable.
CREATE OR REPLACE PACKAGE Emp_data AS TYPE Emp_val_cv_type IS REF CURSOR RETURN Emp_tab%ROWTYPE; PROCEDURE Open_emp_cv (Emp_cv IN OUT Emp_val_cv_type, Dept_number IN INTEGER); PROCEDURE Fetch_emp_data (emp_cv IN Emp_val_cv_type, emp_row OUT Emp_tab%ROWTYPE); END Emp_data; CREATE OR REPLACE PACKAGE BODY Emp_data AS PROCEDURE Open_emp_cv (Emp_cv IN OUT Emp_val_cv_type, Dept_number IN INTEGER) IS BEGIN
9-32
Cursor Variables
OPEN emp_cv FOR SELECT * FROM Emp_tab WHERE deptno = dept_number; END open_emp_cv; PROCEDURE Fetch_emp_data (Emp_cv IN Emp_val_cv_type, Emp_row OUT Emp_tab%ROWTYPE) IS BEGIN FETCH Emp_cv INTO Emp_row; END Fetch_emp_data; END Emp_data;
The following example shows how to call the Emp_data package procedures from a PL/SQL block:
DECLARE -- declare a cursor variable Emp_curs Emp_data.Emp_val_cv_type; Dept_number Dept_tab.Deptno%TYPE; Emp_row Emp_tab%ROWTYPE; BEGIN Dept_number := 20; -- open the cursor using a variable Emp_data.Open_emp_cv(Emp_curs, Dept_number); -- fetch the data and display it LOOP Emp_data.Fetch_emp_data(Emp_curs, Emp_row); EXIT WHEN Emp_curs%NOTFOUND; DBMS_OUTPUT.PUT(Emp_row.Ename || ); DBMS_OUTPUT.PUT_LINE(Emp_row.Sal); END LOOP; END;
Discrim IN POSITIVE) IS BEGIN IF Discrim = 1 THEN OPEN Cv FOR SELECT * FROM Emp_tab WHERE Sal > 2000; ELSIF Discrim = 2 THEN OPEN Cv FOR SELECT * FROM Dept_tab; END IF; END Open_cv; END Emp_dept_data;
You can call the Open_cv procedure to open the cursor variable and point it to either a query on the Emp_tab table or the Dept_tab table. The following PL/SQL block shows how to fetch using the cursor variable, and then use the ROWTYPE_MISMATCH predened exception to handle either fetch:
DECLARE Emp_rec Emp_tab%ROWTYPE; Dept_rec Dept_tab%ROWTYPE; Cv Emp_dept_data.CV_TYPE; BEGIN Emp_dept_data.open_cv(Cv, 1); -- Open Cv For Emp_tab Fetch Fetch cv INTO Dept_rec; -- but fetch into Dept_tab record -- which raises ROWTYPE_MISMATCH DBMS_OUTPUT.PUT(Dept_rec.Deptno); DBMS_OUTPUT.PUT_LINE( || Dept_rec.Loc); EXCEPTION WHEN ROWTYPE_MISMATCH THEN BEGIN DBMS_OUTPUT.PUT_LINE (Row type mismatch, fetching Emp_tab data...); FETCH Cv INTO Emp_rec; DBMS_OUTPUT.PUT(Emp_rec.Deptno); DBMS_OUTPUT.PUT_LINE( || Emp_rec.Ename); END;
9-34
SQL> @proc1
And, if there are one or more errors in the code, then you receive a notice such as the following:
MGR-00072: Warning: Procedure proc1 created with compilation errors
In this case, use the SHOW ERRORS statement in SQL*Plus to get a list of the errors that were found. SHOW ERRORS with no argument lists the errors from the most recent compilation. You can qualify SHOW ERRORS using the name of a procedure, function, package, or package body:
SQL> SHOW ERRORS PROC1 SQL> SHOW ERRORS PROCEDURE PROC1
See Also: See the SQL*Plus Users Guide and Reference for complete
Note: Before issuing the SHOW ERRORS statement, use the SET
LINESIZE statement to get long lines on output. The value 132 is usually a good choice. For example:
SET LINESIZE 132
Assume that you want to create a simple procedure that deletes records from the employee table using SQL*Plus:
CREATE OR REPLACE PROCEDURE Fire_emp(Emp_id NUMBER) AS BEGIN DELETE FROM Emp_tab WHER Empno = Emp_id; END /
Notice that the CREATE PROCEDURE statement has two errors: the DELETE statement has an error (the E is absent from WHERE), and the semicolon is missing after END. After the CREATE PROCEDURE statement is entered and an error is returned, a SHOW ERRORS statement returns the following lines:
SHOW ERRORS; ERRORS FOR PROCEDURE Fire_emp: LINE/COL ERROR
-------------- -------------------------------------------3/27 PL/SQL-00103: Encountered the symbol "EMPNO" wh. . . 5/0 PL/SQL-00103: Encountered the symbol "END" when . . . 2 rows selected.
Notice that each line and column number where errors were found is listed by the SHOW ERRORS statement. Alternatively, you can query the following data dictionary views to list errors when using any tool or application:
s
The error text associated with the compilation of a procedure is updated when the procedure is replaced, and it is deleted when the procedure is dropped. Original source code can be retrieved from the data dictionary using the following views: ALL_SOURCE, USER_SOURCE, and DBA_SOURCE.
See Also: Oracle9i Database Reference for more information about
This procedure stops procedure execution, rolls back any effects of the procedure, and returns a user-specied error number and message (unless the error is trapped by an exception handler). ERROR_NUMBER must be in the range of -20000 to -20999. Error number -20000 should be used as a generic number for messages where it is important to relay information to the user, but having a unique error number is not required. Text must be a character expression, 2 Kbytes or less (longer messages are ignored). Keep_error_stack can be TRUE if you want to add the error to any
9-36
already on the stack, or FALSE if you want to replace the existing errors. By default, this option is FALSE.
Note: Some of the Oracle-supplied packages, such as
DBMS_OUTPUT, DBMS_DESCRIBE, and DBMS_ALERT, use application error numbers in the range -20000 to -20005. See the descriptions of these packages for more information. The RAISE_APPLICATION_ERROR procedure is often used in exception handlers or in the logic of PL/SQL code. For example, the following exception handler selects the string for the associated user-dened error message and calls the RAISE_APPLICATION_ERROR procedure:
... WHEN NO_DATA_FOUND THEN SELECT Error_string INTO Message FROM Error_table, V$NLS_PARAMETERS V WHERE Error_number = -20101 AND Lang = v.value AND v.parameter = "NLS_LANGUAGE"; Raise_application_error(-20101, Message); ...
remote procedures, see"Handling Errors in Remote Procedures" on page 9-40. The following section includes an example of passing a user-specied error number from a trigger to a procedure.
Enter a RAISE statement that names the appropriate exception. A RAISE statement stops the execution of the procedure, and control passes to an exception handler (if any). Call the RAISE_APPLICATION_ERROR procedure to return a user-specied error number and message.
You can also dene an exception handler to handle user-specied error messages. For example, Figure 92 on page 9-39 illustrates the following:
s
An exception and associated exception handler in a procedure A conditional statement that checks for an error (such as transferring funds not available) and enters a user-specied error number and message within a trigger How user-specied error numbers are returned to the calling environment (in this case, a procedure), and how that application can dene an exception that corresponds to the user-specied error number
Declare a user-dened exception in a procedure or package body (private exceptions), or in the specication of a package (public exceptions). Dene an exception handler in the body of a procedure (standalone or package).
9-38
Figure 92
Procedure fire_emp(empid NUMBER) IS invalid_empid EXCEPTION; PRAGMA EXCEPTION_INIT(invalid_empid, 20101); BEGIN DELETE FROM emp WHERE empno = empid; EXCEPTION WHEN invlid_empid THEN INSERT INTO emp_audit VALUES (empid, Fired before probation ended); END;
Table EMP
TRIGGER emp_probation BEFORE DELETE ON emp FOR EACH ROW BEGIN IF (sysdate:old.hiredate)<30 THEN raise_application_error(20101, Employee||old.ename|| on probation) END IF; END;
Unhandled Exceptions
In database PL/SQL program units, an unhandled user-error condition or internal error condition that is not trapped by an appropriate exception handler causes the implicit rollback of the program unit. If the program unit includes a COMMIT statement before the point at which the unhandled exception is observed, then the implicit rollback of the program unit can only be completed back to the previous COMMIT. Additionally, unhandled exceptions in database-stored PL/SQL program units propagate back to client-side applications that call the containing program unit. In such an application, only the application program unit call is rolled back (not the entire application program unit), because it is submitted to the database as a SQL statement. If unhandled exceptions in database PL/SQL program units are propagated back to database applications, then the database PL/SQL code should be modied to handle the exceptions. Your application can also trap for unhandled exceptions when calling database program units and handle such errors appropriately.
PL/SQL user-dened exceptions, which must be declared using the keyword EXCEPTION. PL/SQL predened exceptions, such as NO_DATA_FOUND. SQL errors, such as ORA-00900 and ORA-02015. Application exceptions, which are generated using the RAISE_APPLICATION_ERROR() procedure.
When using local procedures, all of these messages can be trapped by writing an exception handler, such as shown in the following example:
EXCEPTION WHEN ZERO_DIVIDE THEN /* ...handle the exception */
Notice that the WHEN clause requires an exception name. If the exception that is raised does not have a name, such as those generated with RAISE_APPLICATION_ERROR, then one can be assigned using PRAGMA_EXCEPTION_INIT, as shown in the following example:
DECLARE
9-40
... Null_salary EXCEPTION; PRAGMA EXCEPTION_INIT(Null_salary, -20101); BEGIN ... RAISE_APPLICATION_ERROR(-20101, salary is missing); ... EXCEPTION WHEN Null_salary THEN ...
When calling a remote procedure, exceptions are also handled by creating a local exception handler. The remote procedure must return an error number to the local calling procedure, which then handles the exception, as shown in the previous example. Because PL/SQL user-dened exceptions always return ORA-06510 to the local procedure, these exceptions cannot be handled. All other remote exceptions can be handled in the same manner as local exceptions.
Adding extra output statements, to verify execution progress and check data values at certain points within the procedure. Running a separate debugger to analyze execution in greater detail.
DBMS_OUTPUT Package
You can also debug stored procedures and triggers using the DBMS_OUTPUT supplied package. Put PUT and PUT_LINE statements in your code to output the value of variables and expressions to your terminal.
Oracle JDeveloper
Recent releases of JDeveloper have new features for debugging PL/SQL, Java, and multi-language programs. The new debugging features take advantage of the Java Debug Wire Protocol (JDWP). You can get JDeveloper as part of various Oracle product suites. Often, a more recent release is available as a download at http://otn.oracle.com/. Before you can use Oracle JDeveloper or other JDWP-based debuggers to debug stored procedures, you must grant the privileges DEBUG ANY PROCEDURE and DEBUG CONNECT SESSION to the user that will establish the connection between the database and the debugger.
9-42
See Also:
s
Oracle Procedure Builder Developers Guide Oracle9i Supplied PL/SQL Packages and Types Reference for more information about the DBMS_DEBUG, DBMS_DEBUG_JDWP, and DBMS_OUTPUT packages. The PL/SQL page on http://otn.oracle.com/ for information about writing low-level debug code.
A procedure can be called within the body of another procedure or a trigger. A procedure can be interactively called by a user using an Oracle tool. A procedure can be explicitly called within an application, such as a SQL*Forms or a precompiler application. A stored function can be called from a SQL statement in a manner similar to calling a built-in SQL function, such as LENGTH or ROUND.
This section includes some common examples of calling procedures from within these environments.
See Also:
page 9-50.
This line calls the Sal_raise procedure. Emp_id is a variable within the context of the procedure. Recursive procedure calls are allowed within PL/SQL: A procedure can call itself.
these lines with a slash (/) to run the PL/SQL block. An easier way to run a block is to use the SQL*Plus statement EXECUTE, which wraps BEGIN and END statements around the code you enter. For example:
EXECUTE Sal_raise(7369, 200);
Some interactive tools allow session variables to be created. For example, when using SQL*Plus, the following statement creates a session variable:
VARIABLE Assigned_empno NUMBER
After dened, any session variable can be used for the duration of the session. For example, you might run a function and capture the return value using a session variable:
9-44
EXECUTE :Assigned_empno := Hire_emp(JSMITH, President, 1032, SYSDATE, 5000, NULL, 10); PRINT Assigned_empno; ASSIGNED_EMPNO -------------2893
See Also: See the SQL*Plus Users Guide and Reference for SQL*Plus
information. See your tools documentation for information about performing similar operations using your development tool.
In this case, :Empno is a host (bind) variable within the context of the application. To run a procedure within the code of a precompiler application, you must use the EXEC call interface. For example, the following statement calls the Fire_emp procedure in the code of a precompiler application:
EXEC SQL EXECUTE BEGIN Fire_emp1(:Empnum); END; END-EXEC;
See Also: For more information about calling PL/SQL procedures from within 3GL applications, see the following manuals:
s s s
Oracle Call Interface Programmers Guide Pro*C/C++ Precompiler Programmers Guide, SQL*Module for Ada Programmers Guide
You must have the EXECUTE privilege for the standalone procedure or package containing the procedure, or you must have the EXECUTE ANY PROCEDURE system privilege. If you are executing a remote procedure, then you must be granted the EXECUTE privilege or EXECUTE ANY PROCEDURE system privilege directly, not through a role. You must include the owners name in the call. For example:
Note: You may need to set up the following data structures for
domain of the owner of the procedure. The owner must be explicitly granted the necessary object privileges to all objects referenced within the body of the code.
List the values in the order the arguments appear in the procedure declaration. Specify the argument names and corresponding values, in any order.
9-46
For example, these statements each call the procedure Sal_raise to increase the salary of employee number 7369 by 500:
Sal_raise(7369, 500); Sal_raise(Sal_incr=>500, Emp_id=>7369); Sal_raise(7369, Sal_incr=>500);
The rst statement identies the argument values by listing them in the order in which they appear in the procedure specication. The second statement identies the argument values by name and in an order different from that of the procedure specication. If you use argument names, then you can list the arguments in any order. The third statement identies the argument values using a combination of these methods. If you use a combination of order and argument names, then values identied in order must precede values identied by name. If you used the DEFAULT option to dene default values for IN parameters to a subprogram (see the PL/SQL Users Guide and Reference),then you can pass different numbers of actual parameters to the rst subprogram, accepting or overriding the default values as you please. If an actual value is not passed, then the corresponding default value is used. If you want to assign a value to an argument that occurs after an omitted argument (for which the corresponding default is used), then you must explicitly designate the name of the argument, as well as its value.
The following list explains how to properly call remote procedures, depending on the calling environment.
s
Remote procedures (standalone and packaged) can be called from within a procedure, an OCI application, or a precompiler application by specifying the remote procedure name, a database link, and the arguments for the remote procedure.
CREATE OR REPLACE PROCEDURE local_procedure(arg IN NUMBER) AS BEGIN fire_emp1@boston_server(arg); END;
In the previous example, you could create a synonym for FIRE_EMP1@BOSTON_SERVER. This would enable you to call the remote procedure from an Oracle tool application, such as a SQL*Forms application, as well from within a procedure, OCI application, or precompiler application.
CREATE SYNONYM synonym1 for fire_emp1@boston_server; CREATE OR REPLACE PROCEDURE local_procedure(arg IN NUMBER) AS BEGIN synonym1(arg); END;
If you do not want to use a synonym, then you could write a local cover procedure to call the remote procedure.
DECLARE arg NUMBER; BEGIN local_procedure(arg); END;
9-48
binding, runtime binding is used when referencing remote procedures. The user account to which you connect depends on the database link. All calls to remotely stored procedures are assumed to perform updates; therefore, this type of referencing always requires two-phase commit of that transaction (even if the remote procedure is read-only). Furthermore, if a transaction that includes a remote procedure call is rolled back, then the work done by the remote procedure is also rolled back. A procedure called remotely can usually execute a COMMIT, ROLLBACK, or SAVEPOINT statement, the same as a local procedure. However, there are some differences in behavior:
s
If the transaction was originated by a non-Oracle database, as may be the case in XA applications, these operations are not allowed in the remote procedure. After doing one of these operations, the remote procedure cannot start any distributed transactions of its own. If the remote procedure does not commit or roll back its work, the commit is done implicitly when the database link is closed. In the meantime, further calls to the remote procedure are not allowed because it is still considered to be performing a transaction.
A distributed update modies data on two or more nodes. A distributed update is possible using a procedure that includes two or more remote updates that access data on different nodes. Statements in the construct are sent to the remote nodes, and the execution of the construct succeeds or fails as a unit. If part of a distributed update fails and part succeeds, then a rollback (of the entire transaction or to a savepoint) is required to proceed. Consider this when creating procedures that perform distributed updates. Pay special attention when using a local procedure that calls a remote procedure. If a timestamp mismatch is found during execution of the local procedure, then the remote procedure is not run, and the local procedure is invalidated.
Hide the identity of the name and owner of a procedure or package. Provide location transparency for remotely stored procedures (standalone or within a package).
When a privileged user needs to call a procedure, an associated synonym can be used. Because the procedures dened within a package are not individual objects (the package is the object), synonyms cannot be created for individual procedures within a package.
Increase user productivity by extending SQL. Expressiveness of the SQL statement increases where activities are too complex, too awkward, or unavailable with SQL. Increase query efciency. Functions used in the WHERE clause of a query can lter data using criteria that would otherwise need to be evaluated by the application. Manipulate character strings to represent special datatypes (for example, latitude, longitude, or temperature). Provide parallel query execution: If the query is parallelized, then SQL statements in your PL/SQL function may also be run in parallel (using the parallel query option).
9-50
PL/SQL functions can be placed wherever an Oracle function can be placed within a SQL statement, or, wherever expressions can occur in SQL. For example, they can be called from the following:
s
The select list of the SELECT statement. The condition of the WHERE and HAVING clause. The CONNECT BY, START WITH, ORDER BY, and GROUP BY clauses. The VALUES clause of the INSERT statement. The SET clause of the UPDATE statement.
You cannot call stored PL/SQL functions from a CHECK constraint clause of a CREATE or ALTER TABLE statement or use them to specify a default value for a column. These situations require an unchanging denition.
Note: Unlike functions, which are called as part of an expression,
procedures are called as statements. Therefore, PL/SQL procedures are not directly callable from SQL statements. However, functions called from a PL/SQL statement or referenced in a SQL expression can call a PL/SQL procedure.
For example, to reference a function you created that is called My_func, in the My_funcs_pkg package, in the Scott schema, that takes two numeric parameters, you could call the following:
SELECT Scott.My_funcs_pkg.My_func(10,20) FROM dual;
Naming Conventions
If only one of the optional schema or package names is given, then the rst identier can be either a schema name or a package name. For example, to determine whether Payroll in the reference Payroll.Tax_rate is a schema or package name, Oracle proceeds as follows:
s
Oracle rst checks for the Payroll package in the current schema.
If the PAYROLL package is found in the current schema, then Oracle looks for a Tax_rate function in the Payroll package. If a Tax_rate function is not found in the Payroll package, then an error message is returned. If a Payroll package is not found, then Oracle looks for a schema named Payroll that contains a top-level Tax_rate function. If the Tax_rate function is not found in the Payroll schema, then an error message is returned.
You can also refer to a stored top-level function using any synonym that you have dened for it.
Name Precedence
In SQL statements, the names of database columns take precedence over the names of functions with no parameters. For example, if schema Scott creates the following two objects:
CREATE TABLE Emp_tab(New_sal NUMBER ...); CREATE FUNCTION New_sal RETURN NUMBER IS ...;
Then, in the following two statements, the reference to New_sal refers to the column Emp_tab.New_sal:
SELECT New_sal FROM Emp_tab; SELECT Emp_tab.New_sal FROM Emp_tab;
Example of Calling a PL/SQL Function from SQL For example, to call the Tax_rate PL/SQL function from schema Scott, run it against the Ss_no and sal columns in Tax_table, and place the results in the variable Income_tax, specify the following:
9-52
DECLARE Tax_id NUMBER; Income_tax NUMBER; BEGIN SELECT scott.tax_rate (Ss_no, Sal) INTO Income_tax FROM Tax_table WHERE Ss_no = Tax_id; END;
Arguments
To pass any number of arguments to a function, supply the arguments within the parentheses. You must use positional notation; named notation is not currently supported. For functions that do not accept arguments, use ().
When calling Gross_pay from a procedural statement, you can always accept the default value of St_hrs. This is because you can use named notation, which lets you skip parameters. For example:
IF Gross_pay(Eenum, Ot_hrs => Otime) > Pay_limit THEN ...
However, when calling Gross_pay from a SQL expression, you cannot accept the default value of St_hrs, unless you accept the default value of Ot_hrs. This is because you cannot use named notation.
Privileges
To call a PL/SQL function from SQL, you must either own or have EXECUTE privileges on the function. To select from a view dened with a PL/SQL function, you must have SELECT privileges on the view. No separate EXECUTE privileges are necessary to select from the view.
It must be a stored function, not a function dened within a PL/SQL block or subprogram. It must be a row function, not a column (group) function; in other words, it cannot take an entire column of data as its argument. All its formal parameters must be IN parameters; none can be an OUT or IN OUT parameter. The datatypes of its formal parameters must be Oracle Server internal types, such as CHAR, DATE, or NUMBER, not PL/SQL types, such as BOOLEAN, RECORD, or TABLE. Its return type (the datatype of its result value) must be an Oracle Server internal type.
For example, the following stored function meets the basic requirements:
9-54
Note: You may need to set up the following data structures for
CREATE FUNCTION Gross_pay (Emp_id IN NUMBER, St_hrs IN NUMBER DEFAULT 40, Ot_hrs IN NUMBER DEFAULT 0) RETURN NUMBER AS St_rate NUMBER; Ot_rate NUMBER; BEGIN SELECT Srate, Orate INTO St_rate, Ot_rate FROM Payroll WHERE Acctno = Emp_id; RETURN St_hrs * St_rate + Ot_hrs * Ot_rate; END Gross_pay;
This change provides uniform support for stored functions written in PL/SQL, Java, and C, and it allows programmers the most exibility possible.
page 9-60.
Restrictions
When a SQL statement is run, checks are made to see if it is logically embedded within the execution of an already running SQL statement. This occurs if the statement is run from a trigger or from a function that was in turn called from the already running SQL statement. In these cases, further checks occur to determine if the new SQL statement is safe in the specic context. The following restrictions are enforced:
s
A function called from a query or DML statement may not end the current transaction, create or rollback to a savepoint, or ALTER the system or session. A function called from a query (SELECT) statement or from a parallelized DML statement may not execute a DML statement or otherwise modify the database. A function called from a DML statement may not read or modify the particular table being modied by that DML statement.
These restrictions apply regardless of what mechanism is used to run the SQL statement inside the function or trigger. For example:
9-56
They apply to a SQL statement called from PL/SQL, whether embedded directly in a function or trigger body, run using the new native dynamic mechanism (EXECUTE IMMEDIATE), or run using the DBMS_SQL package. They apply to statements embedded in Java with SQLJ syntax or run using JDBC. They apply to statements run with OCI using the callback context from within an "external" C function.
You can avoid these restrictions if the execution of the new SQL statement is not logically embedded in the context of the already running statement. PL/SQLs new autonomous transactions provide one escape. Another escape is available using OCI from an external C function, if you create a new connection, rather than using the handle available from the OCIExtProcContext argument.
Declaring a Function
The keywords DETERMINISTIC and PARALLEL_ENABLE can be used in the syntax for declaring a function. These are optimization hints, informing the query optimizer and other software components about those functions that need not be called redundantly and about those that may be used within a parallelized query or parallelized DML statement. Only functions that are DETERMINISTIC are allowed in function-based indexes and in certain snapshots and materialized views. A function that is dependent solely on the values passed into it as arguments, and does not meaningfully reference or modify the contents of package variables or the database, or have any other side-effects, is called deterministic. Such a function reliably produces the exact same result value for any particular combination of argument values passed into it. The DETERMINISTIC keyword is placed after the return value type in a declaration of the function. For example:
CREATE FUNCTION F1 (P1 NUMBER) RETURN NUMBER DETERMINISTIC IS BEGIN RETURN P1 * 2; END;
This keyword may be placed on a function dened in a CREATE FUNCTION statement, in a functions declaration in a CREATE PACKAGE statement, or on a methods declaration in a CREATE TYPE statement. It should not be repeated on the functions or methods body in a CREATE PACKAGE BODY or CREATE TYPE BODY statement.
Certain performance optimizations occur on calls to functions that are marked DETERMINISTIC, without any other action being required. However, the database has no reasonable way to recognize if the functions behavior indeed is truly deterministic. If the DETERMINISTIC keyword is applied to a function whose behavior is not truly deterministic, then the result of queries involving that function is unpredictable. Two relatively new features require that any function used with them is declared DETERMINISTIC.
s
Any function used in a function-based index is required to be DETERMINISTIC. Any function used in a materialized view must be DETERMINISTIC if that view is to be marked ENABLE QUERY REWRITE.
Both of these features attempt to use previously calculated results rather than calling the function when it is possible to do so. It is also preferable that only functions declared DETERMINISTIC are used in any materialized view or snapshot that is declared REFRESH FAST. Oracle allows in REFRESH FAST snapshots those functions that have a PRAGMA RESTRICT_REFERENCES noting that they are RNDS, and those PL/SQL functions dened with a CREATE FUNCTION statement whose code can be examined to determine that they do not read the database nor call any other routine which might, as these have been allowed historically. Functions that are used in a WHERE, ORDER BY, or GROUP BY clause, are MAP or ORDER methods of a SQL type, or in any other way are part of determining whether or where a row should appear in a result set also should be DETERMINISTIC as discussed previously. Oracle cannot require that they be explicitly declared DETERMINISTIC without breaking existing applications, but the use of the keyword might be a wise choice of style within your application.
9-58
the original session. Java STATIC class attributes are similarly initialized and modied independently in each process. Because a function can use package (or Java STATIC) variables to accumulate some value across the various rows it encounters, Oracle cannot assume that it is safe to parallelize the execution of all user-dened functions. For query (SELECT) statements, in previous releases, the parallel query optimization looked to see if a function was noted as RNPS and WNPS in a PRAGMA RESTRICT_REFERENCES declaration; those functions that were marked as both RNPS and WNPS could be run in parallel. Functions dened with a CREATE FUNCTION statement had their code implicitly examined to determine if they were actually pure enough; parallelized execution might occur even though a pragma cannot be specied on these functions.
See Also: "Using PRAGMA RESTRICT_REFERENCES" on
page 9-60. For DML statements, in previous releases, the parallelization optimization looked to see if a function was noted as having all four of RNDS, WNDS, RNPS and WNPS specied in a PRAGMA RESTRICT_REFERENCES declaration; those functions that were marked as neither reading nor writing to either the database or package variables could run in parallel. Again, those functions dened with a CREATE FUNCTION statement had their code implicitly examined to determine if they were actually pure enough; parallelized execution might occur even though a pragma cannot be specied on these functions. In Oracle9i, we continue to parallelize those functions that earlier releases would recognize as parallelizable. The PARALLEL_ENABLE keyword is the preferred way now to mark your code as safe for parallel execution. This keyword is syntactically similar to DETERMINISTIC as described previously; it is placed after the return value type in a declaration of the function, as in:
CREATE FUNCTION F1 (P1 NUMBER) RETURN NUMBER PARALLEL_ENABLE IS BEGIN RETURN P1 * 2; END;
This keyword may be placed on a function dened in a CREATE FUNCTION statement, in a functions declaration in a CREATE PACKAGE statement, or on a methods declaration in a CREATE TYPE statement. It should not be repeated on the functions or methods body in a CREATE PACKAGE BODY or CREATE TYPE BODY statement.
Note that a PL/SQL function that is dened with CREATE FUNCTION may still be run in parallel without any explicit declaration that it is safe to do so, if the system can determine that it neither reads nor writes package variables nor calls any function that might do so. A Java method or C function is never seen by the system as safe to run in parallel unless the programmer explicitly indicates PARALLEL_ENABLE on the "call specication" or provides a PRAGMA RESTRICT_REFERENCES indicating that the function is sufciently pure. An additional runtime restriction is imposed on functions run in parallel as part of a parallelized DML statement. Such a function is not permitted to in turn execute a DML statement; it is subject to the same restrictions that are enforced on functions that are run inside a query (SELECT) statement.
See Also: "Restrictions" on page 9-56.
Where:
Keyword Description
Writes no database state (does not modify database tables). Reads no database state (does not query database tables). Writes no package state (does not change the values of packaged variables). Reads no package state (does not reference the values of packaged variables). Allows easy calling from functions that do have RESTRICT_REFERENCES declarations to those that do not.
9-60
You can pass the arguments in any order. If any SQL statement inside the function body violates a rule, then you get an error when the statement is parsed. In the following example, the function compound neither reads nor writes database or package state; therefore, you can assert the maximum purity level. Always assert the highest purity level that a function allows. That way, the PL/SQL compiler never rejects the function unnecessarily.
Note: You may need to set up the following data structures for
CREATE PACKAGE Finance AS -- package specification FUNCTION Compound (Years IN NUMBER, Amount IN NUMBER, Rate IN NUMBER) RETURN NUMBER; PRAGMA RESTRICT_REFERENCES (Compound, WNDS, WNPS, RNDS, RNPS); END Finance; CREATE PACKAGE BODY Finance AS --package body FUNCTION Compound (Years IN NUMBER, Amount IN NUMBER, Rate IN NUMBER) RETURN NUMBER IS BEGIN RETURN Amount * POWER((Rate / 100) + 1, Years); END Compound; -- no pragma in package body END Finance;
-- function call
FROM WHERE
Using the Keyword TRUST The keyword TRUST in the RESTRICT_REFERENCES syntax allows easy calling from functions that have RESTRICT_REFERENCES declarations to those that do not. When TRUST is present, the restrictions listed in the pragma are not actually enforced, but rather are simply trusted to be true. When calling from a section of code that is using pragmas to one that is not, there are two likely usage styles. One is to place a pragma on the routine to be called, for example on a "call specication" for a Java method. Then, calls from PL/SQL to this method will complain if the method is less restricted than the calling function. For example:
CREATE OR REPLACE PACKAGE P1 IS FUNCTION F1 (P1 NUMBER) RETURN NUMBER IS LANGUAGE JAVA NAME CLASS1.METHODNAME(int) return int; PRAGMA RESTRICT_REFERENCES(F1,WNDS,TRUST); FUNCTION F2 (P1 NUMBER) RETURN NUMBER; PRAGMA RESTRICT_REFERENCES(F2,WNDS); END; CREATE OR REPLACE PACKAGE BODY P1 IS FUNCTION F2 (P1 NUMBER) RETURN NUMBER IS BEGIN RETURN F1(P1); END; END;
Here, F2 can call F1, as F1 has been declared to be WNDS. The other approach is to mark only the caller, which may then make a call to any function without complaint. For example:
CREATE OR REPLACE PACKAGE P1a IS FUNCTION F1 (P1 NUMBER) RETURN NUMBER IS LANGUAGE JAVA NAME CLASS1.METHODNAME(int) return int; FUNCTION F2 (P1 NUMBER) RETURN NUMBER; PRAGMA RESTRICT_REFERENCES(F2,WNDS,TRUST); END; CREATE OR REPLACE PACKAGE BODY P1a IS FUNCTION F2 (P1 NUMBER) RETURN NUMBER IS BEGIN RETURN F1(P1);
9-62
END; END;
Here, F2 can call F1 because while F2 is promised to be WNDS (because TRUST is specied), the body of F2 is not actually examined to determine if it truly satises the WNDS restriction. Because F2 is not examined, its call to F1 is allowed, even though there is no PRAGMA RESTRICT_REFERENCES for F1. Differences between Static and Dynamic SQL Statements. Static INSERT, UPDATE, and DELETE statements do not violate RNDS if these statements do not explicitly read any database states, such as columns of a table. However, dynamic INSERT, UPDATE, and DELETE statements always violate RNDS, regardless of whether or not the statements explicitly read database states. The following INSERT violates RNDS if its executed dynamically, but it does not violate RNDS if its executed statically.
INSERT INTO my_table values(3, SCOTT);
The following UPDATE always violates RNDS statically and dynamically, because it explicitly reads the column name of my_table.
UPDATE my_table SET id=777 WHERE name=SCOTT;
Package States
The state of a nonreusable package (one not marked SERIALLY_REUSABLE) persists for the lifetime of a session. A packages state includes global variables, cursors, and so on. The state of a serially reusable package persists only for the lifetime of a call to the server. On a subsequent call to the server, if a reference is made to the serially reusable package, then Oracle creates a new instantiation of the serially reusable package and initializes all the global variables to NULL or to the default values provided. Any changes made to the serially reusable package state in the previous calls to the server are not visible.
9-64
on a call to the server does not necessarily imply that Oracle allocates memory or congures the instantiation object. Oracle looks for an available instantiation work area (which is allocated and congured) for this package in a least-recently used (LRU) pool in the SGA. At the end of the call to the server, this work area is returned back to the LRU pool. The reason for keeping the pool in the SGA is that the work area can be reused across users who have requests for the same package.
A package specication can be marked serially reusable, whether or not it has a corresponding package body. If the package has a body, then the body must have the serially reusable pragma, if its corresponding specication has the pragma; it cannot have the serially reusable pragma unless the specication also has the pragma.
Its package variables are meant for use only within the work boundaries, which correspond to calls to the server (either OCI call boundaries or PL/SQL RPC calls to the server).
Note: If the application programmer makes a mistake and
depends on a package variable that is set in a previous unit of work, then the application program can fail. PL/SQL cannot check for such cases. A pool of package instantiations is kept, and whenever a "unit of work" needs this package, one of the instantiations is "reused", as follows:
s
The package variables are reinitialized (for example, if the package variables have default values, then those values are reinitialized). The initialization code in the package body is run again.
At the "end work" boundary, cleanup is done. If any cursors were left open, then they are silently closed. Some non-reusable secondary memory is freed (such as memory for collection variables or long VARCHAR2s). This package instantiation is returned back to the pool of reusable instantiations kept for this package.
Serially reusable packages cannot be accessed from within triggers. If you attempt to access a serially reusable package from a trigger, then Oracle issues the error message "cannot access Serially Reusable package <string> in the context of a trigger."
9-66
Suppose your Enterprise Manager (or SQL*Plus) application issues the following:
CONNECT Scott/Tiger # first CALL to server BEGIN Sr_pkg.N := 10; END; # second CALL to server BEGIN DBMS_OUTPUT.PUT_LINE(Sr_pkg.N); END;
SERIALLY_REUSABLE, the program would have printed '10'. Example 2: How Package Variables Act Across Call Boundaries This example has both a package specication and package body, which are serially reusable.
CONNECT Scott/Tiger DROP PACKAGE Sr_pkg; CREATE OR REPLACE PACKAGE Sr_pkg IS PRAGMA SERIALLY_REUSABLE; TYPE Str_table_type IS TABLE OF VARCHAR2(200) INDEX BY BINARY_INTEGER; Num NUMBER := 10; Str VARCHAR2(200) := 'default-init-str';
Str_tab STR_TABLE_TYPE; PROCEDURE Print_pkg; PROCEDURE Init_and_print_pkg(N NUMBER, V VARCHAR2); END Sr_pkg; CREATE OR REPLACE PACKAGE BODY Sr_pkg IS -- the body is required to have the pragma because the -- specification of this package has the pragma PRAGMA SERIALLY_REUSABLE; PROCEDURE Print_pkg IS BEGIN DBMS_OUTPUT.PUT_LINE('num: ' || Sr_pkg.Num); DBMS_OUTPUT.PUT_LINE('str: ' || Sr_pkg.Str); DBMS_OUTPUT.PUT_LINE('number of table elems: ' || Sr_pkg.Str_tab.Count); FOR i IN 1..Sr_pkg.Str_tab.Count LOOP DBMS_OUTPUT.PUT_LINE(Sr_pkg.Str_tab(i)); END LOOP; END; PROCEDURE Init_and_print_pkg(N NUMBER, V VARCHAR2) IS BEGIN -- init the package globals Sr_pkg.Num := N; Sr_pkg.Str := V; FOR i IN 1..n LOOP Sr_pkg.Str_tab(i) := V || ' ' || i; END LOOP; -- now print the package Print_pkg; END; END Sr_pkg; SET SERVEROUTPUT ON;
9-68
Initing and printing pkg state.. num: 4 str: abracadabra number of table elems: 4 abracadabra 1 abracadabra 2 abracadabra 3 abracadabra 4 Printing package state in the same CALL... num: 4 str: abracadabra number of table elems: 4 abracadabra 1 abracadabra 2 abracadabra 3 abracadabra 4
REM SR package access in subsequent CALL: BEGIN -- print the package in the next call to the server. -- We should that the package state is reset to the initial (default) values. DBMS_OUTPUT.PUT_LINE('Printing package state in the next CALL...'); Sr_pkg.Print_pkg; END; Statement processed. Printing package state in the next CALL... num: 10 str: default-init-str number of table elems: 0
Example 3: Open Cursors in Serially Reusable Packages Across Call Boundaries This example demonstrates that any open cursors in serially reusable packages get closed automatically at the end of a work boundary (which is a call). Also, in a new call, these cursors need to be opened again.
REM REM REM REM REM REM For serially reusable pkg: At the end work boundaries (which is currently the OCI call boundary) all open cursors will be closed. Because the cursor is closed - every time we fetch we will start at the first row again.
CREATE TABLE People (Name VARCHAR2(20)); INSERT INTO People VALUES ('ET'); INSERT INTO People VALUES ('RAMBO'); CREATE OR REPLACE PACKAGE Sr_pkg IS PRAGMA SERIALLY_REUSABLE; CURSOR C IS SELECT Name FROM People; END Sr_pkg; SQL> SET SERVEROUTPUT ON; SQL> CREATE OR REPLACE PROCEDURE Fetch_from_cursor IS Name VARCHAR2(200); BEGIN IF (Sr_pkg.C%ISOPEN) THEN DBMS_OUTPUT.PUT_LINE('cursor is already open.'); ELSE DBMS_OUTPUT.PUT_LINE('cursor is closed; opening now.'); OPEN Sr_pkg.C; END IF; -- fetching from cursor. FETCH sr_pkg.C INTO name; DBMS_OUTPUT.PUT_LINE('fetched: ' || Name); FETCH Sr_pkg.C INTO name; DBMS_OUTPUT.PUT_LINE('fetched: ' || Name); -- Oops forgot to close the cursor (Sr_pkg.C). -- But, because it is a Serially Reusable pkg's cursor, -- it will be closed at the end of this CALL to the server. END; EXECUTE fetch_from_cursor; cursor is closed; opening now. fetched: ET fetched: RAMBO
9-70
In this technique:
s
The producer function uses the PIPELINED keyword in its declaration. The producer function uses an OUT parameter that is a record, corresponding to a row in the result set. As each output record is completed, it is sent to the consumer function using the PIPE ROW keyword. The producer function ends with a RETURN statement that does not specify any return value. The consumer function or SQL statement uses the TABLE keyword to treat the resulting rows like a regular table.
For example:
CREATE FUNCTION StockPivot(p refcur_pkg.refcur_t) RETURN TickerTypeSet PIPELINED IS out_rec TickerType := TickerType(NULL,NULL,NULL); in_rec p%ROWTYPE; BEGIN LOOP -- Function accepts multiple rows through a REF CURSOR argument. FETCH p INTO in_rec; EXIT WHEN p%NOTFOUND; -- Return value is a record type that matches the table definition. out_rec.ticker := in_rec.Ticker; out_rec.PriceType := O; out_rec.price := in_rec.OpenPrice; -- Once a result row is ready, we send it back to the calling program, -- and continue processing. PIPE ROW(out_rec); -- This function outputs twice as many rows as it receives as input. out_rec.PriceType := C; out_rec.Price := in_rec.ClosePrice; PIPE ROW(out_rec); END LOOP; CLOSE p; -- The function ends with a RETURN statement that does not specify any value. RETURN; END; / -- Here we use the result of this function in a SQL query. SELECT * FROM TABLE(StockPivot(CURSOR(SELECT * FROM StockTable)));
-- Here we use the result of this function in a PL/SQL block. DECLARE total NUMBER := 0; price_type VARCHAR2(1); BEGIN FOR item IN (SELECT * FROM TABLE(StockPivot(CURSOR(SELECT * FROM StockTable)))) LOOP -- Access the values of each output row. -- We know the column names based on the declaration of the output type. -- This computation is just for illustration. total := total + item.price; price_type := item.price_type; END LOOP; END; /
Code the member functions. In particular, ODCIAggregateIterate accumulates the result as it is called once for each row that is processed. Store any intermediate results using the attributes of the object type. Create the aggregate function, and associate it with the new object type. Call the aggregate function from SQL queries, DML statements, or other places that you might use the built-in aggregates. You can include typical options such as DISTINCT and ALL in the calls to the aggregate function.
See Also: Oracle9i Data Cartridge Developers Guide for complete
details of this process and the requirements for the member functions.
9-72
10
Calling External Procedures
In situations where a particular language does not provide the features you need, or when you want to reuse existing code written in another language, you can use code written in some other language by calling external procedures. This chapter discusses the following topics:
s
Overview of Multi-Language Programs What Is an External Procedure? Overview of The Call Specication for External Procedures Loading External Procedures Publishing External Procedures Publishing Java Class Methods Publishing External C Procedures Locations of Call Specications Passing Parameters to Java Class Methods with Call Specications Passing Parameters to External C Procedures with Call Specications Executing External Procedures with the CALL Statement Handling Errors and Exceptions in Multi-Language Programs Using Service Procedures with External C Procedures Doing Callbacks with External C Procedures
PL/SQL, as described in the PL/SQL Users Guide and Reference C, by means of the Oracle Call Interface (OCI), as described in the Oracle Call Interface Programmers Guide C or C++, by means of the Pro*C/C++ precompiler, as described in the Pro*C/C++ Precompiler Programmers Guide COBOL, by means of the Pro*COBOL precompiler, as described in the Pro*COBOL Precompiler Programmers Guide Visual Basic, by means of Oracle Objects For OLE (OO4O), as described in the Oracle Objects for OLE/ActiveX Programmers Guide Java, by means of the JDBC Application Programmers Interface (API), as described in Oracle8 Database Programming with Java.
How should you choose between these different implementation possibilities? Each of these languages offers different advantages: ease of use, the availability of programmers with specic expertise, the need for portability, and the existence of legacy code are powerful determinants. The choice may narrow depending on how your application needs to work with Oracle:
s
PL/SQL is a powerful development tool, specialized for SQL transaction processing. Some computation-intensive tasks are executed most efciently in a lower level language, such as C. The need for portability, together with the need for security, may inuence you to select Java.
Most signicantly, from the point of view of performance, you should note that only PL/SQL and Java methods run within the address space of the server. C/C++ methods are dispatched as external procedures, and run on the server machine but outside the address space of the database server. Pro*COBOL and Pro*C are precompilers, and Visual Basic accesses Oracle through the OCI, which is implemented in C. Taking all these factors into account suggests that there may be a number of situations in which you may need to implement your application in more than one language. For instance, the introduction of Java running within the address space of
10-2
the server suggest that you may want to import existing Java applications into the database, and then leverage this technology by calling Java functions from PL/SQL and SQL. Until Oracle 8.0, the Oracle RDBMS supported SQL and the stored procedure language PL/SQL. In Oracle 8.0, PL/SQL introduced external procedures, which allowed the capability of writing C functions as PL/SQL bodies. These C functions are callable directly from PL/SQL, and from SQL through PL/SQL procedure calls. With 8.1, Oracle provides a special-purpose interface, the call specication, that lets you call external procedures from other languages. While this service is designed for intercommunication between SQL, PL/SQL, C, and Java, it is accessible from any base language that can call these languages. For example, your procedure can be written in a language other than Java or C and still be usable by SQL or PL/SQL, as long as your procedure is callable by C. Therefore, if you have a candidate C++ procedure, you would use a C++ extern "C" statement in that procedure to make it callable by C. This means that the strengths and capabilities of different languages are available to you, regardless of your programmatic environment. You are not restricted to one language with its inherent limitations. External procedures promote reusability and modularity because you can deploy specic languages for specic purposes.
Move computation-bound programs from client to server where they execute faster (because they avoid the round-trips of network communication) Interface the database server with external systems and data sources
Dispatching the appropriate C or Java target procedure Datatype conversions Parameter mode mappings Automatic memory allocation and cleanup Purity constraints to be specied, where necessary, for packaged functions called from SQL. Calling Java methods or C procedures from database triggers Location exibility: you can put AS LANGUAGE call specications in package or type specications, or package (or type) bodies to optimize performance and hide implementation details
To use an already-existing program as an external procedure, load, publish, and then call it.
10-4
For help in creating a DLL, look in the RDBMS subdirectory /public, where a template makefile can be found.
Creating a class libunit in schema scott from le Agent.class requires two steps: First, create a directory object on the servers le system. The name of the directory object is an alias for the directory path leading to Agent.class. To create the directory object, you must grant user scott the CREATE ANY DIRECTORY privilege, then execute the CREATE DIRECTORY statement, as follows:
CONNECT System/Manager GRANT CREATE ANY DIRECTORY TO Scott IDENTIFIED BY Tiger; CONNECT Scott/Tiger CREATE DIRECTORY Bfile_dir AS /home/java/bin;
The name of the libunit is derived from the name of the class. Alternatively, you can use the command-line utility LoadJava. This uploads Java binaries and resources into a system-generated database table, then uses the CREATE JAVA statement to load the Java les into RDBMS libunits. You can upload Java les from le systems, Java IDEs, intranets, or the Internet.
The Listener sets a few required environment variables (such as ORACLE_HOME, ORACLE_SID, and LD_LIBRARY_PATH) for the external procedure agent. It can also dene specic environment variables in the ENVS section of its listener.ora entry, and these variables are passed to the agent process. Otherwise, it provides the agent with a "clean" environment. The environment variables set for the agent are independent of those set for the client and server. Therefore, external procedures, which run in the agent process, cannot read environment variables set for the client or server processes.
10-6
themselves by using the standard C procedures setenv() and getenv(), respectively. Environment variables, set this way, are specic to the agent process, which means that they can be read by all functions executed in that process, but not by any other process running on the same host.
You must specify the full path to the DLL, because the linker cannot resolve references to just the DLL name. In the following example, you create alias library c_utils, which represents DLL utils.so:
CREATE LIBRARY C_utils AS /DLLs/utils.so;
To allow exibility in specifying the DLLs, you can specify the root part of the path as an environment variable using the notation ${VAR_NAME}, and set up that variable in the ENVS section of the listener.ora entry. In the following example, the agent specied by the name agent_link is used to run any external procedure in the library C_Utils. The environment variable EP_LIB_HOME is expanded by the agent to the appropriate path for that instance, such as /usr/bin/dll.
create or replace database link agent_link using agent_tns_alias; create or replace library C_utils is ${EP_LIB_HOME}/utils.so agent agent_link;
Notes:
a. b.
On a Windows system, you would specify the path using a drive letter and backslash characters (\) in the path. This technique is not applicable for VMS systems, where the ENVS section of listener.ora is not supported.
For a C procedure:
s
The alias library corresponding to the DLL for a C procedure. The name of the C procedure in a DLL. Various options for specifying how parameters are passed. Which parameter (if any) holds the name of the external procedure agent, for running the procedure on a different machine.
You begin the declaration using the normal CREATE OR REPLACE syntax for a procedure, function, package specication, package body, type specication, or type body. The call specication follows the name and parameter declarations. Its syntax is:
{IS | AS} LANGUAGE {C | JAVA}
10-8
Procedure, but replaces the ANSI keyword AS EXTERNAL with this call specication syntax. This new syntax, introduced for Java class methods, has now been extended to C procedures. This is then followed by either:
NAME java_string_literal_name
Where library_name is the name of your alias library, c_string_literal_name is the name of your external C procedure, and external_parameter stands for:
{ CONTEXT | SELF [{TDO | property}] | {parameter_name | RETURN} [property] [BY REFERENCE] [external_datatype]}
LIBRARY
Species a local alias library. (You cannot use a database link to specify a remote library.) The library name is a PL/SQL identier. Therefore, if you enclose the name in double quotes, then it becomes case sensitive. (By default, the name is stored in upper case.) You must have EXECUTE privileges on the alias library.
NAME
Species the external C procedure to be called. If you enclose the procedure name in double quotes, then it becomes case sensitive. (By default, the name is stored in upper case.) If you omit this subclause, then the procedure name defaults to the upper-case name of the PL/SQL subprogram.
Note: The terms LANGUAGE and CALLING STANDARD apply
LANGUAGE
Species the third-generation language in which the external procedure was written. If you omit this subclause, then the language name defaults to C.
CALLING STANDARD
Species the Windows NT calling standard (C or Pascal) under which the external procedure was compiled. (Under the Pascal Calling Standard, arguments are reversed on the stack, and the called function must pop the stack.) If you omit this subclause, then the calling standard defaults to C.
WITH CONTEXT
Species that a context pointer will be passed to the external procedure. The context data structure is opaque to the external procedure but is available to service procedures called by the external procedure.
PARAMETERS
Species the positions and datatypes of parameters passed to the external procedure. It can also specify parameter properties, such as current length and maximum length, and the preferred parameter passing method (by value or by reference).
AGENT IN
Species which parameter holds the name of the agent process that should run this procedure. This is intended for situations where external procedure agents are run using multiple agent processes, to ensure robustness if one external procedure crashes its agent process. You can pass the name of the agent process (corresponding to the name of a database link), and if tnsnames.ora and listener.ora are set up properly across both instances, the external procedure is invoked on the other instance. Both instances must be on the same host. This is similar to the AGENT clause of the CREATE LIBRARY statement; specifying the value at runtime through AGENT IN allows greater exibility. When the agent name is specied this way, it overrides any agent name declared in the alias library. If no agent name is specied, the default is the extproc agent on the same instance as the calling program.
The NAME-clause string uniquely identies the Java method. The PL/SQL function or procedure and Java must correspond with regard to parameters. If the Java method takes no parameters, then you must code an empty parameter list for it. When you load Java classes into the RDBMS, they are not published to SQL automatically. This is because the methods of many Java classes are called only from other Java classes, or take parameters for which there is no appropriate SQL type. Suppose you want to publish the following Java method named J_calcFactorial, which returns the factorial of its argument:
package myRoutines.math; public class Factorial { public static int J_calcFactorial (int n) { if (n == 1) return 1; else return n * J_calcFactorial(n - 1); }
10-11
The following call specication publishes Java method J_calcFactorial as PL/SQL stored function plsToJavaFac_func, using SQL*Plus:
CREATE OR REPLACE FUNCTION Plstojavafac_func (N NUMBER) RETURN NUMBER AS LANGUAGE JAVA NAME myRoutines.math.Factorial.J_calcFactorial(int) return int;
Standalone PL/SQL Procedures and Functions PL/SQL Package Specications PL/SQL Package Bodies Object Type Specications Object Type Bodies
Note: Under Oracle 8.0, AS EXTERNAL call specications could not be placed in package or type bodies.
We have already shown an example of call specication located in a standalone PL/SQL function. Here are some examples showing some of the other locations.
clauses may or may not be required to fully stipulate a call specication. See the Invoker-rights section of this manual for rules on their placement and defaults.
10-13
CREATE OR REPLACE TYPE Demo_typ AUTHID DEFINER AS OBJECT (Attribute1 VARCHAR2(2000), SomeLib varchar2(20), MEMBER PROCEDURE plsToC_demoExternal_proc (x BINARY_INTEGER, y VARCHAR2, z DATE) AS LANGUAGE C NAME "C_demoExternal" LIBRARY SomeLib WITH CONTEXT -- PARAMETERS(CONTEXT, x INT, y STRING, z OCIDATE) PARAMETERS(CONTEXT, x INT, y STRING, z OCIDATE, SELF) );
10-15
END; CREATE OR REPLACE PACKAGE BODY Demo_pack AS PROCEDURE plsToC_InBodyOld_proc (x BINARY_INTEGER, y VARCHAR2, z DATE) AS EXTERNAL LANGUAGE C NAME "C_InBodyOld" LIBRARY SomeLib WITH CONTEXT PARAMETERS(CONTEXT, x INT, y STRING, z OCIDATE); PROCEDURE plsToC_demoExternal_proc (x BINARY_INTEGER, y VARCHAR2, z DATE) AS LANGUAGE C NAME "C_demoExternal" LIBRARY SomeLib WITH CONTEXT PARAMETERS(CONTEXT, x INT, y STRING, z OCIDATE); PROCEDURE plsToC_InBody_proc (x BINARY_INTEGER, y VARCHAR2, z DATE) AS LANGUAGE C NAME "C_InBody" LIBRARY SomeLib WITH CONTEXT PARAMETERS(CONTEXT, x INT, y STRING, z OCIDATE); PROCEDURE plsToJ_InBody_proc (x BINARY_INTEGER, y VARCHAR2, z DATE) IS LANGUAGE JAVA NAME pkg1.class4.J_InBody_meth(int,java.lang.String,java.sql.Date); END;
The available set of PL/SQL datatypes does not correspond one-to-one with the set of C datatypes.
Unlike C, PL/SQL includes the RDBMS concept of nullity. Therefore, PL/SQL parameters can be NULL, whereas C parameters cannot. The external procedure might need the current length or maximum length of CHAR, LONG RAW, RAW, and VARCHAR2 parameters. The external procedure might need characterset information about CHAR, VARCHAR2, and CLOB parameters. PL/SQL might need the current length, maximum length, or null status of values returned by the external procedure.
In the following sections, you learn how to specify a parameter list that deals with these circumstances.
Note: The maximum number of parameters that you can pass to a C
external procedure is 128. However, if you pass oat or double parameters by value, then the maximum is less than 128. How much less depends on the number of such parameters and your operating system. To get a rough estimate, count each oat or double passed by value as two parameters.
Specifying Datatypes
Do not pass parameters to an external procedure directly. Instead, pass them to the PL/SQL subprogram that published the external procedure. Therefore, you must specify PL/SQL datatypes for the parameters. Each PL/SQL datatype maps to a default external datatype, as shown in Table 101.
Table 101 Parameter Datatype Mappings
PL/SQL Type BINARY_INTEGER BOOLEAN PLS_INTEGER Supported External Types [UNSIGNED] CHAR [UNSIGNED] SHORT [UNSIGNED] INT [UNSIGNED] LONG SB1, SB2, SB4 UB1, UB2, UB4 SIZE_T Default External Type INT
10-17
FLOAT REAL DOUBLE PRECISION CHAR CHARACTER LONG NCHAR NVARCHAR2 ROWID VARCHAR VARCHAR2 LONG RAW RAW BFILE BLOB CLOB NCLOB NUMBER DATE TIMESTAMP TIMESTAMP WITH TIME ZONE TIMESTAMP WITH LOCAL TIME ZONE INTERVAL DAY TO SECOND INTERVAL YEAR TO MONTH
RAW OCILOBLOCATOR
OCIInterval
OCIInterval dvoid
composite object types: OCICOLL collections (varrays, nested tables, index-by tables
External Datatype Corresponding to PL/SL Type CHAR UNSIGNED CHAR SHORT UNSIGNED SHORT INT UNSIGNED INT LONG UNSIGNED LONG CHAR UNSIGNED CHAR SHORT UNSIGNED SHORT
unsigned char unsigned char * unsigned char * short unsigned short int unsigned int long short * unsigned short * int * unsigned int * long * short * unsigned short * int * unsigned int * long *
unsigned char unsigned char * unsigned char * short unsigned short short * unsigned short * short * unsigned short *
10-19
External Datatype Corresponding to PL/SL Type INT UNSIGNED INT LONG UNSIGNED LONG SIZE_T SB1 UB1 SB2 UB2 SB4 UB4 FLOAT DOUBLE STRING RAW OCILOBLOCATOR OCINUMBER OCISTRING OCIRAW OCIDATE OCICOLL
unsigned long unsigned long * unsigned long * size_t sb1 ub1 sb2 ub2 sb4 ub4 float double char * size_t * sb1 * ub1 * sb2 * ub2 * sb4 * ub4 * float * double * char * size_t * sb1 * ub1 * sb2 * ub2 * sb4 * ub4 * float * double * char *
unsigned char unsigned char * unsigned char * * OCILobLocator OCILobLocator * ** OCINumber * OCIString * OCIRaw * OCIDate * OCINumber * OCIString * OCIRaw * OCIDate * OCILobLocator ** OCINumber * OCIString * OCIRaw * OCIDate *
OCIColl * or OCIColl ** or OCIColl ** or OCIArray *, OCIArray **, or OCIArray **, or or OCITable * OCITable ** OCITable ** OCIType * OCIType * OCIType *
OCITYPE
External Datatype Corresponding to PL/SL Type TDO ADT (final types) ADT (non-final types)
Composite object types are not self describing. Their description is stored in a Type Descriptor Object (TDO). Objects and indicator structs for objects have no predened OCI datatype, but must use the datatypes generated by Oracles Object Type Translator (OTT). The optional TDO argument for INDICATOR, and for composite objects, in general, has the C datatype, OCIType *. OCICOLL for REF and collection arguments is optional and only exists for the sake of completeness. You cannot map REFs or collections onto any other datatype and vice versa.
10-21
All IN and RETURN arguments of external types not on the above list, all IN OUT arguments, and all OUT arguments are passed by reference.
CREATE OR REPLACE FUNCTION Interp_func ( /* Find the value of y at x degrees using Lagrange interpolation: */ x IN FLOAT, y IN FLOAT) RETURN FLOAT AS LANGUAGE C NAME "Interp_func" LIBRARY MathLib;
Each formal parameter declaration species a name, parameter mode, and PL/SQL datatype (which maps to the default external datatype). That might be all the information the external procedure needs. If not, then you can provide more information using the PARAMETERS clause, which lets you specify the following:
s
Nondefault external datatypes The current and/or maximum length of a parameter NULL/NOT NULL indicators for parameters Characterset IDs and forms The position of parameters in the list How IN parameters are passed (by value or by reference)
For every formal parameter, there must be a corresponding parameter in the PARAMETERS clause. If you include the WITH CONTEXT clause, then you must specify the parameter CONTEXT, which shows the position of the context pointer in the parameter list. If the external procedure is a function, the parameter RETURN must be in the last position if specied. If RETURN is not specied, the default external type is used.
Specifying Properties
You can also use the PARAMETERS clause to pass additional information about PL/SQL formal parameters and function results to an external procedure. Do this by specifying one or more of the following properties:
INDICATOR [{STRUCT | TDO}] LENGTH MAXLEN CHARSETID CHARSETFORM SELF
The following table shows the allowed and the default external datatypes, PL/SQL datatypes, and PL/SQL parameter modes allowed for a given property. Notice that MAXLEN (used to specify data returned from C back to PL/SQL) cannot be applied to an IN parameter.
10-23
Table 103
Allowed Default External Types External Type (C) (C) SHORT SHORT Allowed PL/SQL Types all scalars Default PL/SQL Allowed Passing PL/SQL Modes Method IN IN OUT OUT RETURN IN IN OUT OUT RETURN IN OUT OUT RETURN BY BY BY BY BY BY BY BY VALUE REFERENCE REFERENCE REFERENCE VALUE REFERENCE REFERENCE REFERENCE
Property INDICATOR
LENGTH
INT [UNSIGNED] SHORT [UNSIGNED] INT [UNSIGNED] LONG INT [UNSIGNED] SHORT [UNSIGNED] INT [UNSIGNED] LONG
CHAR LONG RAW RAW VARCHAR2 CHAR LONG RAW RAW VARCHAR2
MAXLEN
[UNSIGNED] INT CHAR CHARSETID [UNSIGNED] CLOB CHARSETFORM SHORT VARCHAR2 [UNSIGNED] INT [UNSIGNED] LONG
BY BY BY BY
In the following example, the PARAMETERS clause species properties for the PL/SQL formal parameters and function result:
CREATE OR REPLACE FUNCTION plsToCparse_func x IN BINARY_INTEGER, Y IN OUT CHAR) RETURN CHAR AS LANGUAGE C LIBRARY c_utils NAME "C_parse" PARAMETERS ( x, -- stores value of x x INDICATOR, -- stores null status of y, -- stores value of y y LENGTH, -- stores current length y MAXLEN, -- stores maximum length RETURN INDICATOR, RETURN); (
x of y of y
The additional parameters in the C prototype correspond to the INDICATOR (for x), LENGTH (of y), and MAXLEN (of y), as well as the INDICATOR for the function result in the PARAMETERS clause. The parameter RETURN corresponds to the C function identier, which stores the result value.
INDICATOR
An INDICATOR is a parameter whose value indicates whether or not another parameter is NULL. PL/SQL does not need indicators, because the RDBMS concept of nullity is built into the language. However, an external procedure might need to know if a parameter or function result is NULL. Also, an external procedure might need to signal the server that a returned value is actually a NULL, and should be treated accordingly. In such cases, you can use the property INDICATOR to associate an indicator with a formal parameter. If the PL/SQL subprogram is a function, then you can also associate an indicator with the function result, as shown above. To check the value of an indicator, you can use the constants OCI_IND_NULL and OCI_IND_NOTNULL. If the indicator equals OCI_IND_NULL, then the associated parameter or function result is NULL. If the indicator equals OCI_IND_NOTNULL, then the parameter or function result is not NULL. For IN parameters, which are inherently read-only, INDICATOR is passed by value (unless you specify BY REFERENCE) and is read-only (even if you specify BY REFERENCE). For OUT, IN OUT, and RETURN parameters, INDICATOR is passed by reference by default. The INDICATOR can also have a STRUCT or TDO option. Because specifying INDICATOR as a property of an object is not supported, and because arguments of objects have complete indicator structs instead of INDICATOR scalars, you must specify this by using the STRUCT option. You must use the type descriptor object (TDO) option for composite objects and collections,
10-25
MAXLEN, you can specify parameters that store the current length and maximum length of a formal parameter.
Note: With a parameter of type RAW or LONG RAW, you must use
the property LENGTH. Also, if that parameter is IN OUT and NULL or OUT and NULL, then you must set the length of the corresponding C parameter to zero. For IN parameters, LENGTH is passed by value (unless you specify BY REFERENCE) and is read-only. For OUT, IN OUT, and RETURN parameters, LENGTH is passed by reference. As mentioned above, MAXLEN does not apply to IN parameters. For OUT, IN OUT, and RETURN parameters, MAXLEN is passed by reference and is read-only.
data with the OCI, see Oracle Call Interface Programmers Guide and the Oracle9i Globalization and National Language Support Guide.
Repositioning Parameters
Remember, each formal parameter of the external procedure must have a corresponding parameter in the PARAMETERS clause. Their positions can differ, because PL/SQL associates them by name, not by position. However, the PARAMETERS clause and the C prototype for the external procedure must have the same number of parameters, and they must be in the same order.
Using SELF
SELF is the always-present argument of an object types member function or procedure, namely the object instance itself. In most cases, this argument is implicit and is not listed in the argument list of the PL/SQL procedure. However, SELF must be explicitly specied as an argument of the PARAMETERS clause. For example, assume that a user wants to create a Person object, consisting of a persons name and date of birth, and then further a table of this object type. The user would eventually like to determine the age of each Person in this table.
Note: You may need to set up data structures similar to the
This example is only for Solaris; other libraries and include paths might be needed for other platforms. In SQL*Plus, the Person object type can be created by:
CREATE OR REPLACE TYPE Person1_typ AS OBJECT ( Name VARCHAR2(30), B_date DATE, MEMBER FUNCTION calcAge_func RETURN NUMBER, PRAGMA RESTRICT_REFERENCES(calcAge_func, WNDS) );
10-27
Normally, the member function would be implemented in PL/SQL, but for this example, we make it an external procedure. To realize this, the body of the member function is declared as follows:
CREATE OR REPLACE TYPE BODY Person1_typ AS MEMBER FUNCTION calcAge_func RETURN NUMBER AS LANGUAGE C NAME "age" LIBRARY agelib WITH CONTEXT PARAMETERS ( CONTEXT, SELF, SELF INDICATOR STRUCT, SELF TDO, RETURN INDICATOR ); END;
Notice that the calcAge_func member function doesnt take any arguments, but only returns a number. A member function is always invoked on an instance of the associated object type. The object instance itself always is an implicit argument of the member function. To refer to the implicit argument, the SELF keyword is used. This is incorporated into the external procedure syntax by supporting references to SELF in the parameters clause. Now the matching table is created and populated.
CREATE TABLE Person_tab OF Person1_typ; INSERT INTO Person_tab VALUES (SCOTT, TO_DATE(14-MAY-85)); INSERT INTO Person_tab VALUES (TIGER, TO_DATE(22-DEC-71));
Sample C code, implementing the "external" member function, and the Object-Type-Translator (OTT)-generated struct definitions are included below.
#include <oci.h> struct PERSON { OCIString *NAME; OCIDate B_DATE; }; typedef struct PERSON PERSON; struct PERSON_ind { OCIInd _atomic; OCIInd NAME; OCIInd B_DATE; }; typedef struct PERSON_ind PERSON_ind; OCINumber *age (ctx, person_obj, person_obj_ind, tdo, ret_ind) OCIExtProcContext *ctx; PERSON *person_obj; PERSON_ind *person_obj_ind; OCIType *tdo; OCIInd *ret_ind; { sword err; text errbuf[512]; OCIEnv *envh; OCISvcCtx *svch; OCIError *errh; OCINumber *age; int inum = 0; sword status;
/* get OCI Environment */ err = OCIExtProcGetEnv( ctx, &envh, &svch, &errh ); /* initialize return age to 0 */ age = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); status = OCINumberFromInt(errh, &inum, sizeof(inum), OCI_NUMBER_SIGNED, age); if (status != OCI_SUCCESS) {
10-29
/* return NULL if the person object is null or the birthdate is null */ if ( person_obj_ind->_atomic == OCI_IND_NULL || person_obj_ind->B_DATE == OCI_IND_NULL ) { *ret_ind = OCI_IND_NULL; return (age); } /* The actual implementation to calculate the age is left to the reader, but an easy way of doing this is a callback of the form: select trunc(months_between(sysdate, person_obj->b_date) / 12) from dual; */ *ret_ind = OCI_IND_NOTNULL; return (age);
}
This is rather than the default, which would be used when there is no PARAMETERS clause:
void C_findRoot(float x);
WITH CONTEXT
By including the WITH CONTEXT clause, you can give an external procedure access to information about parameters, exceptions, memory allocation, and the user environment. The WITH CONTEXT clause species that a context pointer will be passed to the external procedure. For example, if you write the following PL/SQL function:
CREATE OR REPLACE FUNCTION getNum_func ( x IN REAL) RETURN BINARY_INTEGER AS LANGUAGE C LIBRARY c_utils NAME "C_getNum" WITH CONTEXT PARAMETERS ( CONTEXT, x BY REFERENCE, RETURN INDICATOR);
The context data structure is opaque to the external procedure; but, is available to service procedures called by the external procedure. If you also include the PARAMETERS clause, then you must specify the parameter CONTEXT, which shows the position of the context pointer in the parameter list. If you omit the PARAMETERS clause, then the context pointer is the rst parameter passed to the external procedure.
10-31
Anonymous blocks Standalone and packaged subprograms Methods of an object type Database triggers SQL statements (calls to packaged functions only).
Although the CALL statement, described below, is conned to SELECTs, it can appear in either the WHERE clause or the SELECT list.
Note: To call a packaged function from SQL statements, you must use
the pragma RESTRICT_REFERENCES, which asserts the purity level of the function (the extent to which the function is free of side effects). PL/SQL cannot check the purity level of the corresponding external procedure. Therefore, make sure that the procedure does not violate the pragma. Otherwise, you might get unexpected results. Any PL/SQL block or subprogram executing on the server side, or on the client side, (for example, in a tool such as Oracle Forms) can call an external procedure. On the server side, the external procedure runs in a separate process address space, which safeguards your database. Figure 101 shows how Oracle and external procedures interact.
External C Process
Preliminaries
Before you call your external procedure, you might want to make sure you understand the execution environment. Specically, you might be interested in privileges, permissions, and synonyms.
Privileges
When external procedures are called through CALL specications, they execute with deners privileges, rather than with the privileges of their invoker. An invokers-privileges program is not bound to a particular schema. It executes at the calling site and accesses database items (such as tables and views) with the callers visibility and permissions. However, a deners privileges program is bound to the schema in which it is dened. It executes at the dening site, in the deners schema, and accesses database items with the deners visibility and permissions.
10-33
Managing Permissions
Note: You may need to set up the following data structures for
To call external procedures, a user must have the EXECUTE privilege on the call specication and on any resources used by the procedure. In SQL*Plus, you can use the GRANT and REVOKE data control statements to manage permissions. For example:
GRANT EXECUTE ON plsToJ_demoExternal_proc TO Public; REVOKE EXECUTE ON plsToJ_demoExternal_proc FROM Public; GRANT EXECUTE ON JAVA RESOURCE "appImages" TO Public; GRANT EXECUTE ON plsToJ_demoExternal_proc TO Scott; REVOKE EXECUTE ON plsToJ_demoExternal_proc FROM Scott;
See Also:
s
This is essentially the same as executing a procedure foo() using a SQL statement of the form "SELECT foo(...) FROM dual," except that the overhead associated with performing the SELECT is not incurred. For example, here is an anonymous PL/SQL block which uses dynamic SQL to call plsToC_demoExternal_proc, which we published above. PL/SQL passes three parameters to the external C procedure C_demoExternal_proc.
DECLARE xx NUMBER(4); yy VARCHAR2(10); zz DATE; BEGIN EXECUTE IMMEDIATE CALL plsToC_demoExternal_proc(:xxx, :yyy, :zzz) USING xx,yy,zz; END;
The semantics of the CALL statement is identical to the that of an equivalent BEGIN..END block.
Note: CALL is the only SQL statement that cannot be put, by itself, in a PL/SQL BEGIN...END block. It can be part of an EXECUTE IMMEDIATE statement within a BEGIN...END block.
The result:
Y -----120
10-35
After the external procedure completes, the agent remains active throughout your Oracle session; when you log off, the agent is killed. Consequently, you incur the cost of launching the agent only once, no matter how many calls you make. Still, you should call an external procedure only when the computational benets outweigh the cost. You can run the agent on a separate machine from your database server. For details, see "Loading External C Procedures" on page 10-6. Here, we call PL/SQL function plsCallsCdivisor_func, which we published above, from an anonymous block. PL/SQL passes the two integer parameters to external function Cdivisor_func, which returns their greatest common divisor.
DECLARE g BINARY_INTEGER; a BINARY_INTEGER; b BINARY_INTEGER; CALL plsCallsCdivisor_func(a, b); IF g IN (2,4,8) THEN ...
C Exception Handling
C programs can raise exceptions through the OCIExtproc... functions.
OCIExtProcAllocCallMemory
This service routine allocates n bytes of memory for the duration of the external procedure call. Any memory allocated by the function is freed automatically as soon as control returns to PL/SQL.
10-37
Note: The external procedure does not need to (and should not)
call the C function free() to free memory allocated by this service routine as this is handled automatically. The C prototype for this function is as follows:
dvoid *OCIExtProcAllocCallMemory( OCIExtProcContext *with_context, size_t amount);
The parameters with_context and amount are the context pointer and number of bytes to allocate, respectively. The function returns an untyped pointer to the allocated memory. A return value of zero indicates failure. In SQL*Plus, suppose you publish external function plsToC_concat_func, as follows:
Note: You may need to set up data structures similar to the
CREATE OR REPLACE FUNCTION plsToC_concat_func ( str1 IN VARCHAR2, str2 IN VARCHAR2) RETURN VARCHAR2 AS LANGUAGE C NAME "concat" LIBRARY stringlib WITH CONTEXT PARAMETERS ( CONTEXT, str1 STRING, str1 INDICATOR short, str2 STRING, str2 INDICATOR short, RETURN INDICATOR short, RETURN LENGTH short,
RETURN STRING);
When called, C_concat concatenates two strings, then returns the result:
select plsToC_concat_func(hello , world) from dual; PLSTOC_CONCAT_FUNC(HELLO,WORLD) ----------------------------------------------------------------------------hello world
If either string is NULL, the result is also NULL. As the following example shows, C_concat uses OCIExtProcAllocCallMemory to allocate memory for the result string:
#include #include #include #include #include <stdio.h> <stdlib.h> <string.h> <oci.h> <ociextp.h>
char *concat(ctx, str1, str1_i, str2, str2_i, ret_i, ret_l) OCIExtProcContext *ctx; char *str1; short str1_i; char *str2; short str2_i; short *ret_i; short *ret_l; { char *tmp; short len; /* Check for null inputs. */ if ((str1_i == OCI_IND_NULL) || (str2_i == OCI_IND_NULL)) { *ret_i = (short)OCI_IND_NULL; /* PL/SQL has no notion of a NULL ptr, so return a zero-byte string. */ tmp = OCIExtProcAllocCallMemory(ctx, 1); tmp[0] = '\0'; return(tmp); } /* Allocate memory for result string, including NULL terminator. */ len = strlen(str1) + strlen(str2); tmp = OCIExtProcAllocCallMemory(ctx, len + 1); strcpy(tmp, str1); strcat(tmp, str2);
10-39
/* Set NULL indicator and length. */ *ret_i = (short)OCI_IND_NOTNULL; *ret_l = len; /* Return pointer, which PL/SQL frees later. */ return(tmp);
} #ifdef LATER static void checkerr (/*_ OCIError *errhp, sword status _*/); void checkerr(errhp, status) OCIError *errhp; sword status; { text errbuf[512]; sb4 errcode = 0; switch (status) { case OCI_SUCCESS: break; case OCI_SUCCESS_WITH_INFO: (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); break; case OCI_NEED_DATA: (void) printf("Error - OCI_NEED_DATA\n"); break; case OCI_NO_DATA: (void) printf("Error - OCI_NODATA\n"); break; case OCI_ERROR: (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); (void) printf("Error - %.*s\n", 512, errbuf); break; case OCI_INVALID_HANDLE: (void) printf("Error - OCI_INVALID_HANDLE\n"); break; case OCI_STILL_EXECUTING: (void) printf("Error - OCI_STILL_EXECUTE\n"); break; case OCI_CONTINUE: (void) printf("Error - OCI_CONTINUE\n"); break;
default: break; } } char *concat(ctx, str1, str1_i, str2, str2_i, ret_i, ret_l) OCIExtProcContext *ctx; char *str1; short str1_i; char *str2; short str2_i; short *ret_i; short *ret_l; { char *tmp; short len; /* Check for null inputs. */ if ((str1_i == OCI_IND_NULL) || (str2_i == OCI_IND_NULL)) { *ret_i = (short)OCI_IND_NULL; /* PL/SQL has no notion of a NULL ptr, so return a zero-byte string. */ tmp = OCIExtProcAllocCallMemory(ctx, 1); tmp[0] = '\0'; return(tmp); } /* Allocate memory for result string, including NULL terminator. */ len = strlen(str1) + strlen(str2); tmp = OCIExtProcAllocCallMemory(ctx, len + 1); strcpy(tmp, str1); strcat(tmp, str2);
/* Set NULL indicator and length. */ *ret_i = (short)OCI_IND_NOTNULL; *ret_l = len; /* Return pointer, which PL/SQL frees later. */ return(tmp);
} /*======================================================================*/ int main(char *argv, int argc) { OCIExtProcContext *ctx; char *str1; short str1_i;
10-41
char *str2; short str2_i; short *ret_i; short *ret_l; /* OCI Handles */ OCIEnv *envhp; OCIServer *srvhp; OCISvcCtx *svchp; OCIError *errhp; OCISession *authp; OCIStmt *stmthp; OCILobLocator *clob, *blob; OCILobLocator *Lob_loc;
/* Initialize and Logon */ (void) OCIInitialize((ub4) OCI_DEFAULT, (dvoid * (*)(dvoid (dvoid * (*)(dvoid (void (*)(dvoid *,
(void) OCIEnvInit( (OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0, (dvoid **) 0 ); (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0);
/* Server contexts */ (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0); /* Service context */ (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0); /* Attach to Oracle */ (void) OCIServerAttach( srvhp, errhp, (text *)"", strlen(""), 0); /* Set attribute server context in the service context */ (void) OCIAttrSet ((dvoid *) svchp, OCI_HTYPE_SVCCTX, (dvoid *)srvhp, (ub4) 0, OCI_ATTR_SERVER, (OCIError *) errhp);
(void) OCIHandleAlloc((dvoid *) envhp, (dvoid **)&authp, (ub4) OCI_HTYPE_SESSION,
(size_t) 0, (dvoid **) 0); (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, (dvoid *) "samp", (ub4)4, (ub4) OCI_ATTR_USERNAME, errhp); (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, (dvoid *) "samp", (ub4) 4, (ub4) OCI_ATTR_PASSWORD, errhp);
/* Begin a User Session */ checkerr(errhp, OCISessionBegin ( svchp, errhp, authp, OCI_CRED_RDBMS, (ub4) OCI_DEFAULT));
(void) OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *) authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp);
/* ------- subroutine called here-----------------------*/ printf ("calling concat...\n"); concat(ctx, str1, str1_i, str2, str2_i, ret_i, ret_l);
return 0; } #endif
OCIExtProcRaiseExcp
This service routine raises a predened exception, which must have a valid Oracle error number in the range 1..32767. After doing any necessary cleanup, your external procedure must return immediately. (No values are assigned to OUT or IN OUT parameters.) The C prototype for this function follows:
10-43
The parameters with_context and error_number are the context pointer and Oracle error number. The return values OCIEXTPROC_SUCCESS and OCIEXTPROC_ERROR indicate success or failure. In SQL*Plus, suppose you publish external procedure plsTo_divide_proc, as follows:
CREATE OR REPLACE PROCEDURE plsTo_divide_proc ( dividend IN BINARY_INTEGER, divisor IN BINARY_INTEGER, result OUT FLOAT) AS LANGUAGE C NAME "C_divide" LIBRARY MathLib WITH CONTEXT PARAMETERS ( CONTEXT, dividend INT, divisor INT, result FLOAT);
When called, C_divide nds the quotient of two numbers. As the following example shows, if the divisor is zero, C_divide uses OCIExtProcRaiseExcp to raise the predened exception ZERO_DIVIDE:
void C_divide (ctx, dividend, divisor, result) OCIExtProcContext *ctx; int dividend; int divisor; float *result; { /* Check for zero divisor. */ if (divisor == (int)0) { /* Raise exception ZERO_DIVIDE, which is Oracle error 1476. */ if (OCIExtProcRaiseExcp(ctx, (int)1476) == OCIEXTPROC_SUCCESS) { return; } else { /* Incorrect parameters were passed. */
OCIExtProcRaiseExcpWithMsg
This service routine raises a user-dened exception and returns a user-dened error message. The C prototype for this function follows:
int OCIExtProcRaiseExcpWithMsg( OCIExtProcContext *with_context, size_t error_number, text *error_message, size_t len);
The parameters with_context, error_number, and error_message are the context pointer, Oracle error number, and error message text. The parameter len stores the length of the error message. If the message is a null-terminated string, then len is zero. The return values OCIEXTPROC_SUCCESS and OCIEXTPROC_ERROR indicate success or failure. In the previous example, we published external procedure plsTo_divide_proc. In the example below, you use a different implementation. With this version, if the divisor is zero, then C_divide uses OCIExtProcRaiseExcpWithMsg to raise a user-dened exception:
void C_divide (ctx, dividend, divisor, result) OCIExtProcContext *ctx; int dividend; int divisor; float *result; /* Check for zero divisor. */ if (divisor == (int)0) { /* Raise a user-defined exception, which is Oracle error 20100, and return a null-terminated error message. */ if (OCIExtProcRaiseExcpWithMsg(ctx, (int)20100, "divisor is zero", 0) == OCIEXTPROC_SUCCESS) { return; } else {
10-45
The parameter with_context is the context pointer, and the parameters envh, svch, and errh are the OCI environment, service, and error handles, respectively. The return values OCIEXTPROC_SUCCESS and OCIEXTPROC_ERROR indicate success or failure. Both external C procedures and Java class methods can call-back to the database to do SQL operations. For a working example, see "Demo Program" on page 10-50. Java exceptions:
See Also: Oracle9i Java Stored Procedures Developers Guide
may execute an SQL statement in a different session through OCIlogon. An external C procedure executing on the Oracle server can call a service routine to obtain OCI environment and service handles. With the OCI, you can use callbacks to execute SQL statements and PL/SQL subprograms, fetch data, and manipulate LOBs. Callbacks and external procedures operate in the same user session and transaction context, and so have the same user privileges. In SQL*Plus, suppose you run the following script:
CREATE TABLE Emp_tab (empno NUMBER(10)) CREATE PROCEDURE plsToC_insertIntoEmpTab_proc ( empno BINARY_INTEGER) AS LANGUAGE C NAME "C_insertEmpTab" LIBRARY insert_lib WITH CONTEXT PARAMETERS ( CONTEXT, empno LONG);
Later, you might call service routine OCIExtProcGetEnv from external procedure plsToC_insertIntoEmpTab_proc, as follows:
#include <stdio.h> #include <stdlib.h> #include <oratypes.h> #include <oci.h> /* includes ociextp.h */ ... void C_insertIntoEmpTab (ctx, empno) OCIExtProcContext *ctx; long empno; { OCIEnv *envhp; OCISvcCtx *svchp; OCIError *errhp; int err; ... err = OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp); ... }
10-47
If you do not use callbacks, you do not need to include oci.h; instead, just include ociextp.h.
Restrictions on Callbacks
With callbacks, the following SQL commands and OCI procedures are not supported:
s
Transaction control commands such as COMMIT Data denition commands such as CREATE The following object-oriented OCI procedures:
OCIObjectNew OCIObjectPin OCIObjectUnpin OCIObjectPinCountReset OCIObjectLock OCIObjectMarkUpdate OCIObjectUnmark OCIObjectUnmarkByRef OCIObjectAlwaysLatest
OCIObjectNotAlwaysLatest OCIObjectMarkDeleteByRef OCIObjectMarkDelete OCIObjectFlush OCIObjectFlushRefresh OCIObjectGetTypeRef OCIObjectGetObjectRef OCIObjectExists OCIObjectIsLocked OCIObjectIsDirtied OCIObjectIsLoaded OCIObjectRefresh OCIObjectPinTable OCIObjectArrayPin OCICacheFlush, OCICacheFlushRefresh, OCICacheRefresh OCICacheUnpin OCICacheFree OCICacheUnmark OCICacheGetObjects OCICacheRegister
s
Also, with OCI procedure OCIHandleAlloc, the following handle types are not supported:
OCI_HTYPE_SERVER OCI_HTYPE_SESSION OCI_HTYPE_SVCCTX
10-49
OCI_HTYPE_TRANS
Usually, when an external procedure fails, its prototype is faulty. In other words, the prototype does not match the one generated internally by PL/SQL. This can happen if you specify an incompatible C datatype. For example, to pass an OUT parameter of type REAL, you must specify float *. Specifying float, double *, or any other C datatype will result in a mismatch. In such cases, you might get: lost RPC connection to external routine agent This error, which means that agent extproc terminated abnormally because the external procedure caused a core dump. To avoid errors when declaring C prototype parameters, refer to the tables above.
Demo Program
Also in the PL/SQL demo directory is the script extproc.sql, which demonstrates the calling of an external procedure. The companion le extproc.c contains the C source code for the external procedure. To run the demo, follow the instructions in extproc.sql. You must use the SCOTT/TIGER account, which must have CREATE LIBRARY privileges.
Threading: In the current non-threaded conguration of the agent process, there is only one function active at a time. In the future, however, Oracle might thread the agent process, which would mean that multiple functions can be active at the same time. In that case, it is possible that two or more functions concurrently would try to access the global variable with unsuccessful results. DLL caching: Global variables are also used to store data that is intended to persist beyond the lifetime of a function. For example, consider two functions func1() and func2() trying to pass data to each other. Because of the DLL caching feature, it is possible that after func1()'s completion, the DLL will be unloaded, which results in all global variables losing their values. When func2() is executed, the DLL is reloaded, and all globals are initialized to 0, which will be inconsistent with their values at the completion of func1().
10-51
Never write to IN parameters or overow the capacity of OUT parameters. (PL/SQL does no run time checks for these error conditions.) Never read an OUT parameter or a function result. Always assign a value to IN OUT and OUT parameters and to function results. Otherwise, your external procedure will not return successfully. If you include the WITH CONTEXT and PARAMETERS clauses, then you must specify the parameter CONTEXT, which shows the position of the context pointer in the parameter list. If you include the PARAMETERS clause, and if the external procedure is a function, then you must specify the parameter RETURN in the last position. For every formal parameter, there must be a corresponding parameter in the PARAMETERS clause. Also, make sure that the datatypes of parameters in the PARAMETERS clause are compatible with those in the C prototype, because no implicit conversions are done. With a parameter of type RAW or LONG RAW, you must use the property LENGTH. Also, if that parameter is IN OUT or OUT and null, then you must set the length of the corresponding C parameter to zero.
This feature is available only on platforms that support DLLs. Only C procedures and procedures callable from C code are supported. You cannot pass PL/SQL cursor variables or records to an external procedure. For records, use instances of object types instead. In the LIBRARY subclause, you cannot use a database link to specify a remote library. The maximum number of parameters that you can pass to a external procedure is 128. However, if you pass oat or double parameters by value, then the maximum is less than 128. How much less depends on the number of such parameters and your operating system. To get a rough estimate, count each oat or double passed by value as two parameters.
Part III
Application Security
This part contains the following chapters:
s
Chapter 11, "Database Security Overview for Application Developers" Chapter 12, "Implementing Application Security Policies" Chapter 13, "Proxy Authentication" Chapter 14, "Data Encryption Using DBMS_OBFUSCATION_TOOLKIT"
11
Database Security Overview for Application Developers
This chapter provides a basic understanding of application and database security policies. The following security policy topics are included in this chapter:
s
See Also:
Security Threats and Countermeasures What Information Security Policies Can Cover Features to Use in Establishing Security Policies
Procedural, such as requiring data center employees to display security badges Personnel, such as performing background checks or "vetting" key personnel Physical, such as securing computers in restricted-access facilities Technical, such as implementing strong authentication requirements for critical business systems
Consider whether the appropriate response to a threat is procedural, physical, technical, or personnel-related, or whether the threat can be met by a combination of the above measures. For example, one possible security threat is disruption of critical business systems caused by a malicious person damaging a computer. A physical response to this threat is to secure key business computers in a locked facility. A procedural response is to create system backups at regular intervals. Personnel measures could include background checks on employees who access or manage key business systems. Oracle9i offers many mechanisms which can implement the technical measures of a good security policy.
11-2
The level of security at the application level System and object privileges Database roles Enterprise roles How to grant and revoke privileges and roles How to create, alter, and drop roles How to control role use Level of granularity of access control User attributes which govern access to the database Whether to use encryption How to implement security in three-tier applications
Application Security
Use this feature to attach privileges and roles to each application, while making sure that users do not misuse those roles and privileges when they are not using the application. Use this feature to implement security policies at a high level of granularity; for example, to enforce row level security. Do this by creating security policy functions attached to the table, view, or synonym used by your application. Then, when a user enters a DML statement on that object, Oracle modies that statement dynamically and transparently to the user. Use this feature to set up session-based attributes securely. For example, you can securely store such user attributes as a user name, employee number, and your position in the management hierarchy. You can retrieve that information later in the session and use it for ne-grained access control. Use this feature to base use of roles on user-dened criteria. For example, you could allow use of a role by a user connecting only from a particular IP address, or accessing the database only through a particular middle tier.
Application Context
Fine-Grained Auditing Use this feature to monitor query access based on content. For example, you can monitor users accessing a specic row within a table. This feature can also be used to detect data misuse or serve as an intrusion detection system.
11-4
Oracle Feature
Recommended Use
Use this Oracle9i data server option to enforce ne-grained access control and label-based access control automatically. For example, you can label data Company Condential or Partner Releaseable to automatically limit access to data based on the label of the data and the labels of data a user is permitted to access. By using Oracle Label Security, organizations can implement ne-grained and label-based access control quickly, in many cases without additional programming Use this feature to preserve user identity through a middle tier to the database, without the overhead of a separate database connection. It is able to proxy the user identity and credentials, such as a password or X.509 certicate, through the middle tier to the database. Also, on behalf of a user, it supports auditing of connections. Use this feature to encrypt information, as an extra measure of security.
Proxy Authentication
Data Encryption
See Also:
Tip 1: Enable and Disable Roles Promptly Tip 2: Encapsulate Privileges in Stored Procedures Tip 3: Use Role Passwords Unknown to the User Tip 4: Use Proxy Authentication and a Secure Application Role Tip 5: Use Secure Application Role to Verify IP Address Tip 6: Use Application Context and Fine-Grained Access Control
Give each application distinct roles, where one role should contain all privileges necessary to use the application successfully. Depending on the situation, there might be several roles that contain various privileges, to provide tighter or less restrictive security while executing the application. Each database role should be protected by a password (or by operating system authentication) to prevent unauthorized use. Another role should contain only non-destructive privileges associated with the application (SELECT privileges for specic tables or views associated with the application). The read-only role allows the application user to generate custom reports using ad hoc tools, such as SQL*Plus. However, this role does not allow the application user to modify table data outside the application itself. A role designed for an ad hoc query tool may or may not be protected by a password (or by operating system authentication).
At startup, each application should use the SET ROLE statement to enable one of the database roles associated with that application. If a password is used to authorize the role, then the password must be included in the SET ROLE statement within the application (encrypted by the application, if possible). If the role is authorized by the operating system, then the system administrator must have set up user accounts and applications so that application users get the appropriate operating system privileges when using the application. Upon termination, each application should disable the previously enabled database role.
11-6
by users outside the application. Such use is not controlled by application-based security. Again, virtual private database is the best way to solve this problem. Also, in three-tier systems, it is possible to restrict the users from using the role outside of the application, by using a secure application role.
Specify the roles to enable when a user starts SQL*Plus, using the PRODUCT_USER_PROFILE table. This functionality is similar to that of a precompiler or Oracle Call Interface (OCI) application that issues a SET ROLE statement to enable specic roles upon application startup. Disable the use of the SET ROLE statement for SQL*Plus users with the PRODUCT_USER_PROFILE table. This allows a SQL*Plus user only the privileges associated with the roles enabled when the user started SQL*Plus. Other ad hoc query and reporting tools can also make use of the PRODUCT_USER_PROFILE table to restrict the roles and commands that each user can use while running that product.
See Also: "Ways to Use Application Context with Fine-Grained
Access Control" on page 12-8 "Using Secure Application Role to Ensure Database Connection" on page 11-16 The appropriate tool manual, such as the SQL*Plus Users Guide and Reference
this, you avoid the problem of the user having the SELECT privilege and using it outside the application.
11-8
application role can validate that the user session was created by proxy, and that the user is connecting to the database through an application, and not directly. Consider a situation in which you want to restrict use of an HR administration role to users accessing the database (by proxy) through the middle tier HRSERVER. You could create the following secure access role:
CREATE ROLE admin_role IDENTIFIED USING hr.admin;
Here, hr.admin is a package which performs desired validation. The package can determine if a user is connected by proxy using SYS_CONTEXT (userenv, proxy_userid), or SYS_CONTEXT (userenv, proxy_user), or both return the ID and name of the proxy user (HRSERVER, in this case). If the user attempts to connect directly to the database, the hr.admin package will not allow the role to be set.
Considerations for Using Application-Based Security Security-Related Tasks of Application Administrators Managing Application Privileges Creating Secure Application Roles Associating Privileges with the Users Database Role Protecting Database Objects Through Use of Schemas Managing Object Privileges Enabling and Disabling Roles Granting and Revoking System Privileges and Roles Granting and Revoking Schema Object Privileges and Roles Granting to, and Revoking from, the User Group PUBLIC
Are Application Users Also Database Users? Is Security Enforced in the Application or in the Database?
Auditing
A basic principle of security is accountability through auditing. However, if all actions in the database are performed by One Big Application User, then database auditing cannot hold individual users accountable for their actions. The application must implement its own auditing mechanisms to capture individual users' actions. Strong forms of authentication supported by Oracle Advanced Security (such as, client authentication over SSL, tokens, and so on) cannot be used if the client authenticating to the database is the application, rather than an individual user.
Oracle Feature
Roles
Roles are assigned to database users. Enterprise roles are assigned to enterprise users who, though not created in the database, are known to the database. If application users are not database users, then the usefulness of roles is diminished. Applications must then craft their own mechanisms to distinguish between the privileges which various application users need to access data within the application. This feature enables users and their authorizations to be centrally managed in an LDAP-based directory such as Oracle Internet Directory. While enterprise users do not need to be created in the database, they do need to be known to the database. The One Big Application User model cannot take advantage of user and authorization management in LDAP.
get more data access through the report-writing tool than they would have in the application itself. Security becomes expensive because organizations must implement the same security policies in multiple applications. Each new application requires an expensive reimplementation.
page 12-57
Creating roles for the database application and managing the privileges of each database role Creating and managing the objects used by the application Maintaining and updating the application code, and Oracle procedures and packages, as necessary
Creating Roles to Simplify Application Privilege Management Advantages of Grouping Application Privileges in Roles
1. 2. 3.
Create a VACATION role. Grant all privileges required by the Vacation application to the VACATION role. Grant the VACATION role to all administrative assistants or to a role named ADMIN_ASSISTS (if previously dened).
You can grant the role, rather than many individual privileges, to those users who run the application. Then, as employees change jobs, you need to grant or revoke only one role, rather than many privileges. You can change the privileges associated with an application by modifying only the privileges granted to the role, rather than the privileges held by all users of the application. You can determine which privileges are necessary to run a particular application by querying the ROLE_TAB_PRIVS and ROLE_SYS_PRIVS data dictionary views. You can determine which users have privileges on which applications by querying the DBA_ROLE_PRIVS data dictionary view.
The application must do the necessary validation. For example, the application must validate that the user is in a particular department, check that the user session was created by proxy, from a particular IP address, or that the user was authenticated using an X.509 certicate. To perform the validation, applications
can use session information accessible through SYS_CONTEXT ('userenv', <session_attribute>). The accessible information indicates the way the user was authenticated, the IP address of the client, and whether the user was proxied.
s
The application must issue a SET_ROLE command using dynamic SQL (DBMS_SESSION.SET ROLE).
Example of Creating a Secure Application Role Using Secure Application Role to Ensure Database Connection
Because users can not change security domain inside Dener's Right procedures, secure application roles can only be enabled inside Invoker's Right procedures.
Note:
Create the roles as application roles and specify the authorized package that will enable the roles. In this example, hr.hr_admin is the specied authorized package.
CREATE ROLE admin_role IDENTIFIED USING hr.hr_admin; CREATE ROLE staff_role IDENTIFIED USING hr.hr_admin;
2.
then /* check responsibility being set, then enable the roles without supplying the password */ if (sys_context(hr,role) = admin ) then dbms_session.set_role('admin_role'); else dbms_session.set_role(staff_role); end if; end if; END; END; /* Create a dedicated authentication function for manageability so that changes in authentication policies would not affect the source code of the application - this design is up the application developers */ /* the only policy in this function is that current user must have been authenticated using the proxy user SCOTT */ CREATE OR REPLACE FUNCTION hr.MySecurityCheck RETURN BOOLEAN AS BEGIN /* a simple check to see if current session is authenticated by the proxy user SCOTT */ if (sys_context(userenv,proxy_user) = SCOTT) then return TRUE; else return FALSE; end IF; END;
When enabling the secure application role, Oracle veries that the authorized PL/SQL package is on the calling stack. This step veries that the authorized PL/SQL package is issuing the command to enable the role. Also, when enabling the users default roles, no checking will be performed for application roles.
The ORDER role (for the Order application) contains the UPDATE privilege for the INVENTORY table The INVENTORY role (for the Inventory application) contains the SELECT privilege for the INVENTORY table Several order entry clerks have been granted both the ORDER and INVENTORY roles
In this scenario, an order entry clerk who has been granted both roles, can presumably use the privileges of the ORDER role when running the INVENTORY application to update the INVENTORY table. The problem is that updating the INVENTORY table is not an authorized action when using the INVENTORY application, but only when using the ORDER application. To avoid such problems, consider using either the SET ROLE statement or the SET_ROLE procedure as explained below. You can also use the secure application role feature to allow roles to be set based on criteria you dene. Topics in this section include:
s
Using the SET ROLE Statement Using the SET_ROLE Procedure Examples of Assigning Roles with Static and Dynamic SQL
Anonymous PL/SQL blocks Invokers rights stored procedures (except those invoked from within deners rights procedures)
In both the above cases, the database checks privileges at execution time, not at compilation time. Therefore, the database can validate that a user has the appropriate privileges (that is, that the user has been granted the role that is being set).
If you use DBMS_SESSION.SET_ROLE within an invoker's rights procedure, the role remains in effect until you explicitly disable it. In keeping with the least privilege principle, (that users should have the fewest privileges they need to do their jobs), you should explicitly disable roles set within an invoker's rights procedure, at the end of the procedure.
Note:
Because PL/SQL performs the security check on SQL when an anonymous block is compiled, SET_ROLE will not affect the security role (in other words, it will not affect the roles enabled) for embedded SQL statements or procedure calls.
Suppose you have a role named ACCT that has been granted privileges allowing you to select from table FINANCE in the JOE schema. In this case, the following block fails:
DECLARE n NUMBER; BEGIN SYS.DBMS_SESSION.SET_ROLE(acct); SELECT empno INTO n FROM JOE.FINANCE; END;
The block fails because the security check which veries that you have the SELECT privilege on table JOE.FINANCE occurs at compile time. At compile time, however, the ACCT role is not yet enabled. The role is not enabled until the block is executed. The DBMS_SQL package, by contrast, is not subject to this restriction. When you use this package, the security checks are performed at runtime. Thus, a call to SET_ROLE would affect the SQL executed using calls to the DBMS_SQL package. The following block is, therefore, successful:
CREATE OR REPLACE PROCEDURE dynSQL_proc AUTHID CURRENT_USER AS n NUMBER; BEGIN
SYS.DBMS_SESSION.SET_ROLE(acct); EXECUTE IMMEDIATE select empno from joe.finance INTO n; --other calls to SYS.DBMS_SQL END;
Unique Schemas
Most schemas can be thought of as usernames: the accounts which enable users to connect to a database and access the database objects. However, unique schemas do not allow connections to the database, but are used to contain a related set of objects. Schemas of this sort are created as normal users, yet are not granted the CREATE SESSION system privilege (either explicitly or through a role). However, you must temporarily grant the CREATE SESSION and RESOURCE privilege to such schemas, if you want to use the CREATE SCHEMA statement to create multiple tables and views in a single transaction. For example, the schema objects for a specic application might be owned by a given schema. Application users can connect to the database using typical database usernames and use the application and the corresponding objects, if they have the privileges to do so. However, no user can connect to the database using the schema set up for the application. This conguration prevents access to the associated objects through the schema, and provides another layer of protection for schema objects. In this case, the application could issue an ALTER SESSION SET CURRENT_SCHEMA statement to connect the user to the correct application schema.
Shared Schemas
For many applications, users do not need their own accountsor their own schemasin a database. These users merely need to access an application schema. For example, users John, Firuzeh and Jane are all users of the Payroll application,
and they need access to the Payroll schema on the Finance database. None of them need to create their own objects in the database; in fact, they need only access Payroll objects. To address this issue, Oracle Advanced Security provides enterprise users (schema-independent users). Enterprise users, users managed in a directory service, can access a shared schema. They do not need to be created as database users; they are shared schema users of the database. Instead of creating a user account (that is, a user schema) in each database an enterprise user needs to access, as well as creating the user in the directory, an administrator can create an enterprise user once, in the directory, and point the user at a shared schema that many other enterprise users can also access. In the previous example, if John, Firuzeh and Jane all access the Sales database as well as the Finance database, an administrator need only create a single schema in the Sales database, which all three users can accessinstead of creating an account for each user on the Sales database. In this case, the DBA for the Sales database creates a shared schema called sales_application, as follows:
CREATE USER sales_application IDENTIFIED GLOBALLY AS ;
The mapping between enterprise users and a schema is done in the directory by means of one or more mapping objects. A mapping object maps the Distinguished Name (DN) of a user to a database schema that the user will access. This can be done in one of two ways:
s
A full DN mapping maps the DN of a single directory user to a database schema, thus associating this user with a particular schema on a database. A partial DN mapping maps all users who share part of a DN to a database schema. A partial DN mapping is useful if multiple enterprise users that have something in common are already grouped under some common root in the directory tree. For example, all enterprise users in the directory subtree corresponding to the Engineering Division can be mapped to one shared schema on the bug database. Multiple enterprise users, who share part of their DN, can access the same shared schema.
When the database tries to determine the enterprise users schema in the directory (that is, the schema to which the database will connect the user), it searches for a full DN mapping. If it does not nd a full DN mapping, then it searches for a partial DN. A full DN mapping thus takes precedence over a partial one. For users authenticated by SSL to the database, or whose X.509 certicate or DN from a certicate is proxied to the database, the database uses the DN to search for the user in the directory. For password-authenticated enterprise users, the DN is obtained from the directory. That is, when a username is presented to the database
for authentication (for example, JANE), the database searches internally to nd if there is a local user Jane. If not, the database searches the directory for Jane, and retrieves an associated DN for Jane. Afterwards, the database refers to a mapping object as above to determine the correct shared schema to which Jane connects. If a set of privileges should be granted to a group of users, this can be done by granting roles and privileges to a shared schema. Every user sharing the schema gets these local roles and local privileges in addition to the enterprise roles. Each enterprise user can be mapped to a shared schema on each database that the user needs to access. These schema-independent users thus need not have a dedicated database schema on each database. Shared schemas therefore lowers the cost of managing users in an enterprise.
Object Privileges
End users are typically granted object privileges. An object privilege allows a user to perform a particular action on a specic table, view, sequence, procedure, function, or package. Table 111 summarizes the object privileges available for each type of object.
Table 111 How Privileges Relate to Schema Objects
Applies Applies Applies to Object Privilege to Table? to View? Sequence? ALTER DELETE Yes Yes No Yes Yes No Applies to Procedure? (1) No No
Notes:
1. 2. 3. Stand-alone stored procedures, functions, and public package constructs. Privilege that cannot be granted to a role. Can also be granted for snapshots.
Creating and Implementing a New Role Managing Roles Protecting Role Use
Managing Roles
You can create roles such that their use is authorized using information from the operating system, from a network authentication service, or from an LDAP-based directory. This enables role management to be centralized.
Central management of roles provides many benets. If an employee leaves, for example, all of her roles and permissions can be changed in a single place.
A user who is granted a role protected by a password can enable or disable the role only by supplying the proper password for the role using a SET ROLE statement. If a role is created without any protection, then any grantee can enable or disable it. Separate SET ROLE statements can be used to enable one database role, and disable all other roles of a user. This way, the user cannot use privileges (from a role) which were intended for use with another application. With ad hoc query tools such as SQL*Plus or Enterprise Manager, users can explicitly enable only the roles for which they are authorized. A secure application role can incorporate additional logic to determine under what conditions the role is enabled. The conditions can reference any information available in the user session. This means information accessible through the USERENV application context namespace, such as the IP address from which the session connected, the method of authentication, and whether the user was proxied or not (that is, connected through a middle tier). .
See Also:
s
"Explicitly Enabling Roles" on page 11-27 Oracle9i Database Administrators Guide For information about network authentication services, see Oracle Advanced Security Administrators Guide
Default Roles Explicitly Enabling Roles Enabling and Disabling Roles When OS_ROLES=TRUE Dropping Roles
Default Roles
A default role is automatically enabled for a user when the user creates a session. A users list of default roles should include those which correspond to his or her typical job function. Each user has a list of zero, one, or more default roles. Any role directly granted to a user can potentially be a default role. An indirectly granted role (a role that is granted to a role) cannot be a default role. The number of default roles for a user should not exceed the maximum number of enabled roles that are allowed per user (as specied by the initialization parameter MAX_ENABLED_ROLES). If the number of default roles for a particular user exceeds this maximum, then errors are returned when the user attempts a connection, and the connection is not allowed.
user creates a session. Placing a role in a users list of default roles bypasses authentication for the role, whether it is authorized using a password or through the operating system. A users list of default roles can be set and altered using the SQL statement ALTER USER. If the users list of default roles is specied as ALL, then every role granted to her is automatically added to her list of default roles. Only subsequent modication of the users default role list can remove newly granted roles from her list of default roles. Modications to a users default role list only apply to sessions created after the alteration or role grant; neither method applies to a session in progress at the time of the user alteration or role grant.
He is granted three roles: PAYROLL_CLERK (password BICENTENNIAL) ACCTS_PAY (password GARFIELD) ACCTS_REC (identied externally)
The PAYROLL_CLERK role includes the indirectly granted role PAYROLL_REPORT (identied externally) Morris only default role is PAYROLL_CLERK
Note: You may need to set up the following data structures for
Morris currently enabled roles can be changed from his default role, PAYROLL_CLERK, to ACCTS_PAY and ACCTS_REC, by the following statements:
SET ROLE accts_pay IDENTIFIED BY garfield; SET ROLE accts_pay IDENTIFIED BY accts_rec;
Notice that in the rst statement, multiple roles can be enabled in a single SET ROLE statement. The ALL and ALL EXCEPT options of the SET ROLE statement also allow several roles granted directly to the user to be enabled in one statement:
SET ROLE ALL EXCEPT Payroll_clerk;
This statement shows the use of the ALL EXCEPT option of the SET ROLE statement. Use this option when you want to enable most of a users roles and only disable one or more. Similarly, all of Morris roles can be enabled by the following statement:
SET ROLE ALL;
When using the ALL or ALL EXCEPT options of the SET ROLE statement, all roles to be enabled either must not require a password, or must be authenticated using the operating system. If a role requires a password, then the SET ROLE ALL or ALL EXCEPT statement is rolled back and an error is returned. A user can also explicitly enable any indirectly granted roles granted to him or her through an explicit grant of another role. Morris can thus issue the following statement:
SET ROLE Payroll_report;
Dropping Roles
When you drop a role, the security domains of all users and roles granted that role are immediately changed to reect the absence of the dropped roles privileges. All indirectly granted roles of the dropped role are also removed from affected security domains. Dropping a role automatically removes the role from all users default role lists. Because the creation of objects is not dependent upon the privileges received through a role, no cascading effects regarding objects need to be considered when dropping a role. For example, tables or other objects are not dropped when a role is dropped. You can drop a role using the SQL statement DROP ROLE. For example:
DROP ROLE clerk;
To drop a role, you must have the DROP ANY ROLE system privilege or have been granted the role with the ADMIN OPTION.
Granting System Privileges and Roles Granting System Privileges and Roles with the ADMIN OPTION Revoking System Privileges and Roles
Schema object privileges cannot be granted along with system privileges and roles in the same GRANT statement.
The grantee can grant or revoke the system privilege or role to or from any user or other role in the database. However, a user cannot revoke a role from himself. The grantee can further grant the system privilege or role with the ADMIN OPTION.
A grantee without the ADMIN OPTION cannot perform the above operations. Note also that this option is not valid when granting a role to another role. When a user creates a role, the role is automatically granted to the creator with the ADMIN OPTION. Assume that you grant the NEW_DBA role to MICHAEL with the following statement:
GRANT new_dba TO michael WITH ADMIN OPTION;
Not only can the user MICHAEL use all of the privileges implicit in the NEW_DBA role, but he can grant, revoke, or drop the NEW_DBA role, as necessary. Privileges Required to Grant System Privileges or Roles To grant a system privilege or role, the grantor requires the ADMIN OPTION for all system privileges and roles being granted. Additionally, any user with the GRANT ANY ROLE system privilege can grant any role in a database.
The ADMIN OPTION for a system privilege or role cannot be selectively revoked. To do so, you must rst revoke the privilege or role, and then grant it without the ADMIN OPTION. Privileges Required to Revoke System Privileges and Roles Any user with the ADMIN OPTION for a system privilege or role can revoke the privilege or role from any other database user or role. The user who revokes a privilege or role need not be the user who originally granted it. Additionally, any user with the GRANT ANY ROLE privilege can revoke any role. Cascading Effects of Revoking System Privileges There are no cascading effects when revoking a system privilege related to DDL operations, regardless of whether the privilege was granted with or without the ADMIN OPTION. For example, assume the following:
1.
You grant the CREATE TABLE system privilege to JWARD with the WITH ADMIN OPTION.
2. 3. 4. 5. 6.
JWARD creates a table. JWARD grants the CREATE TABLE system privilege to TSMITH. TSMITH creates a table. You revoke the CREATE TABLE privilege from JWARD. JWARDs table continues to exist. TSMITH continues to have the CREATE TABLE system privilege, and his table still exists.
Cascading effects can be observed when revoking a system privilege related to a DML operation. For example, if SELECT ANY TABLE is granted to a user, and if that user has created any procedures, then all procedures contained in the users schema must be reauthorized before they can be used again (after the revoke).
To grant the INSERT object privilege for only the ENAME and JOB columns of the EMP_TAB table to the users JWARD and TSMITH, enter the following statement:
GRANT INSERT(Ename, Job) ON Emp_tab TO jward, tsmith;
To grant all schema object privileges on the SALARY view to the user WALLEN, use the ALL shortcut. For example:
GRANT ALL ON Salary TO wallen;
System privileges and roles cannot be granted along with schema object privileges in the same GRANT statement. The following section explains granting and revoking schema object privileges. It includes:
s
Granting and Revoking Schema Object Privileges with the GRANT OPTION Revoking Schema Object Privileges
Granting and Revoking Schema Object Privileges with the GRANT OPTION
A schema object privilege can be granted to a user with the GRANT OPTION. This special privilege allows the grantee several expanded privileges:
s
The grantee can grant the schema object privilege to any user or any role in the database. The grantee can also grant the schema object privilege to other users, with or without the GRANT OPTION. If the grantee receives schema object privileges for a table with the GRANT OPTION, and the grantee has the CREATE VIEW or the CREATE ANY VIEW system privilege, then the grantee can create views on the table and grant the corresponding privileges on the view to any user or role in the database.
The user whose schema contains an object is automatically granted all associated schema object privileges with the GRANT OPTION.
Note: The GRANT OPTION is not valid when granting a schema object privilege to a role. Oracle prevents the propagation of schema object privileges through roles, so that grantees of a role cannot propagate object privileges received through roles.
Privileges Required to Grant Schema Object Privileges To grant a schema object privilege, the grantor must either
s
Be the owner of the schema object being specied, or Have received, with the GRANT OPTION, the schema object privileges in question, or Have the GRANT ANY OBJECT PRIVILEGE system privilege, which enables delegation of an owners right to grant and revoke object privileges.
is performed in the usual way. If the user making the grant did not already possess the specic object privilege being granted, the grant is done as if the owner of the object performed it. As with other system privileges, GRANT ANY OBJECT PRIVILEGE can only be granted by a user possessing it WITH ADMIN OPTION.
For the table DEPT_TAB, a grantor could also revoke all privileges that he or she granted to the role HUMAN_RESOURCES by entering the following statement:
REVOKE ALL ON Dept_tab FROM human_resources;
The statement is valid even if only one privilege was granted. Note that this statement would only revoke the privileges that the grantor authorized, not the grants made by other users. The GRANT OPTION for a schema object privilege cannot be selectively revoked; the schema object privilege must be revoked and then regranted without the GRANT OPTION. A user cannot revoke schema object privileges from himself. Revoking Column-Selective Schema Object Privileges Recall that column-specic INSERT, UPDATE, and REFERENCES privileges can be granted for tables or views. However, it is not possible to revoke column-specic privileges selectively with a similar REVOKE statement. Instead, the grantor must rst revoke the schema object privilege for all columns of a table, view, or synonym, and then selectively grant the new column-specic privileges again. For example, assume the role HUMAN_RESOURCES has been granted the UPDATE privilege on the DEPTNO and DNAME columns of the table DEPT_TAB. To revoke the UPDATE privilege on just the DEPTNO column, enter the following two statements:
REVOKE UPDATE ON Dept_tab FROM human_resources; GRANT UPDATE (Dname) ON Dept_tab TO human_resources;
The REVOKE statement revokes the UPDATE privilege on all columns of the DEPT_TAB table from the role HUMAN_RESOURCES. The GRANT statement regrants the UPDATE privilege on the DNAME column to the role HUMAN_RESOURCES.
Revoking the REFERENCES Schema Object Privilege If the grantee of the REFERENCES object privilege has used the privilege to create a foreign key constraint (that currently exists), then the grantor can only revoke the privilege by specifying the CASCADE CONSTRAINTS option in the REVOKE statement:
REVOKE REFERENCES ON Dept_tab FROM jward CASCADE CONSTRAINTS;
When the CASCADE CONSTRAINTS option is specied, any foreign key constraints currently dened that use the revoked REFERENCES privilege are dropped. Privileges Required to Revoke Schema Object Privileges To revoke a schema object privilege, the revoker must normally be the original grantor of the object privilege being revoked. However, a different revoker with the system privilege GRANT ANY OBJECT PRIVILEGE can also succeed, assuming the object privilege being revoked was granted by the original owner of the object. If the object privilege being revoked was granted by someone else, it can be revoked only by that entity, because the system privilege GRANT ANY OBJECT PRIVILEGE only makes it possible to grant/revoke as the original owner. Revoking the GRANT ANY OBJECT PRIVILEGE System Privilege A user possessing the GRANT ANY OBJECT PRIVILEGE system privilege can revoke any specied object privilege granted by the owner, or on behalf of the owner, such as a grant made by some user holding the GRANT ANY OBJECT PRIVILEGE. However, the privileged user is not allowed to revoke grants made by other arbitrary users. Grants that exercise the GRANT ANY OBJECT PRIVILEGE system privilege appear to be executed by the object owner. If a grantor performs an object privilege grant using the GRANT ANY OBJECT PRIVILEGE and this system privilege is later revoked, the grantor will not be able to revoke the granted object privilege. It can, however, still be revoked by the owner or by other users holding the GRANT ANY OBJECT PRIVILEGE. The normal SQL REVOKE syntax species the grantee of the privilege to be revoked but not the granter, as this is always assumed to be the user executing the REVOKE. With the introduction of the GRANT ANY OBJECT PRIVILEGE system privilege, the implied granter could be either the user executing the REVOKE or the owner of the object. In a situation where the object privilege has been granted by both the owner and the user executing the REVOKE, we will only revoke the object privilege granted by the user issuing the REVOKE. For example, assume that a user SCOTT possessing the GRANT ANY OBJECT PRIVILEGE system privilege attempts to revoke an object privilege from another user. If SCOTT previously granted this same object privilege, the grant by SCOTT will be revoked. If the owner granted the
object privilege, but SCOTT did not, then the object privilege from the owner is revoked. Otherwise, the REVOKE will not be allowed. Cascading Effects of Revoking Schema Object Privileges Revoking a schema object privilege can have several cascading effects that should be investigated before a REVOKE statement is issued:
s
Schema object denitions that depend on a DML object privilege can be affected if the DML object privilege is revoked. For example, assume the procedure body of the TEST procedure includes a SQL statement that queries data from the EMP_TAB table. If the SELECT privilege on the EMP_TAB table is revoked from the owner of the TEST procedure, the procedure can no longer be executed successfully. Schema object denitions that require the ALTER and INDEX DDL object privileges are not affected if the ALTER or INDEX object privilege is revoked. For example, if the INDEX privilege is revoked from a user that created an index on someone elses table, the index continues to exist. When a REFERENCES privilege for a table is revoked from a user, any foreign key integrity constraints dened by the user that require the dropped REFERENCES privilege are automatically dropped. For example, assume that the user JWARD is granted the REFERENCES privilege for the DEPTNO column of the DEPT_TAB table and that she creates a foreign key on the DEPTNO column in the EMP_TAB table that references the DEPTNO column. If the REFERENCES privilege on the DEPTNO column of the DEPT_TAB table is revoked, the foreign key constraint on the DEPTNO column of the EMP_TAB table is dropped in the same operation. If a grantors object privilege is revoked, then the schema object privilege grants propagated using the GRANT OPTION are revoked. For example, assume that USER1 is granted the SELECT object privilege with the GRANT OPTION, and grants the SELECT privilege on EMP_TAB to USER2. Subsequently, the SELECT privilege is revoked from USER1. This revoke is cascaded to USER2 as well. Any schema objects that depended on USER1s and USER2s revoked SELECT privilege can also be affected.
How Grants Affect Dependent Objects Issuing a GRANT statement against a schema object causes the "last DDL time" attribute of the object to change. This can invalidate any dependent schema objects, in particular PL/SQL package bodies that refer to the schema object. These then must be recompiled.
may not be needed in your situation. Oracle Corporation highly recommends that system administrators review grants to PUBLIC and revoke privileges that are not absolutely necessary.
This section explains granting and revoking from the user group PUBLIC. It includes:
s
Revoking Security-Vulnerable Packages from PUBLIC Cascading Effects of Revokes from PUBLIC When Grants and Revokes Take Effect
UTL_TCP
Package UTL_HTTP
Reasons Not to Grant EXECUTE to Public Allows a database to request and retrieve data through HTTP. Granting this package to PUBLIC may permit data to be sent through HTML forms to a malicious web site. Allows text level access to any le on the host operating system, if congure improperly. Even when properly congured, this package does not distinguish between its calling applications may write arbitrary data into the same location that is written by another application. Allows one to encrypt stored data. Most users should not have the privilege to encrypt data. Encrypted data may be non-recoverable if the keys are not securely generated, stored, and managed. Oracle recommends that EXECUTE on this package be granted to a role, and the role granted to those users who need to encrypt data.
UTL_FILE
DBMS_RANDOM
These packages are useful to the applications that need them and warrant proper conguration and usage, but they may not be suitable or required for other applications. If necessary, revoke the package from PUBLIC and database users.
All grants/revokes of privileges (system and schema object) to users, roles, or PUBLIC are immediately observed. All grants/revokes of roles to users, other roles, or PUBLIC are observed only when a current user session issues a SET ROLE statement to re-enable the role after the grant/revoke, or when a new user session is created after the grant/revoke.
See Also: "Listing Privilege and Role Information" in the Oracle9i Database Administrators Guide
12
Implementing Application Security Policies
This chapter explains how to implement application security policies. Topics in this chapter include:
s
Introduction to Application Context Introduction to Fine-Grained Access Control Fine-Grained Auditing Enforcing Application Security
Features of Application Context Ways to Use Application Context with Fine-Grained Access Control User Models and Virtual Private Database Creating a Virtual Private Database Policy with Oracle Policy Manager How to Use Application Context Examples: Application Context Within a Fine-Grained Access Control Function Automatic Reparse Introduction to Application Context Accessed Globally Initializing Application Context Externally Initializing Application Context Globally
Specifying Attributes for Each Application Providing Security Validation Providing Access to Predened Attributes Through the USERENV Namespace
12-2
For the General Ledger application context, you can specify the attributes SET_OF_BOOKS and TITLE. For the Order Entry application context, you can specify the attribute CUSTOMER_NUMBER. For the Human Resources application context, you can specify the attributes ORGANIZATION_ID, POSITION, and COUNTRY.
In each case, you can adapt the application context to your precise security needs.
Set 02 is a valid set of books. The user has privileges to access set of books 02.
The validation function can check application metadata tables to make this determination and ensure that the attributes in combination are in line with the overall security policy. To prevent users from changing a context attribute without the above security validation, Oracle ensures that an attribute can be changed only by the designated package which implements the context.
or thick JDBC, you can access the PROXY_USER attribute in the USERENV application context to determine whether the user's session was created by a middle tier application. Your policy function could allow a user to access data only for connections where the user is proxied. If the user is not proxied (that is, when the user connects directly to the database), the user would not be able to access any data. While you can use the PROXY_USER attribute within VPD to ensure that users only access data through a particular middle-tier application, a different approach would be to develop a secure application role. Rather than have each policy ensure that the user accesses the database by being proxied through HRAPPSERVER, you could have the secure application role enforce this. Although predened attributes can be accessed through the USERENV application context, they cannot not be changed. They are listed in Table 121. Use the following syntax to return information about the current session.
SYS_CONTEXT('userenv', 'attribute')
complete details about the USERENV namespace and its predened attributes
12-4
CURRENT_USERID
SESSION_USER SESSION_USERID
CURRENT_SCHEMAID
PROXY_USER PROXY_USERID DB_DOMAIN DB_NAME HOST OS_USER EXTERNAL_NAME IP_ADDRESS NETWORK_PROTOCOL BG_JOB_ID FG_JOB_ID AUTHENTICATION_TYPE AUTHENTICATION_DATA
CURRENT_SQL CLIENT_IDENTIFIER
12-6
Advanced Security.
Using application context with ne-grained access control is called Virtual Private Database (VPD).
Note:
Application context can be used in the following ways with ne-grained access control:
s
Using Application Context as a Secure Data Cache Using Application Context to Return a Specic Predicate (Security Policy) Using Application Context to Provide Attributes Similar to Bind Variables in a Predicate
12-8
to this:
SELECT * FROM Orders_tab WHERE Custno = SYS_CONTEXT (order_entry, cust_num);
Oracle9i VPD capabilities facilitate connection pooling by allowing multiple connections to access one or more global application contexts, instead of setting up an application context for each distinct user session. Applications use a CLIENT_IDENTIFIER (which could be an individual application username, or a group) to reference the global application context. Global application contexts provide additional exibility for web-based applications to use Virtual Private Database, as well as enhanced performance through reuse of common application contexts among multiple sessions instead of setting up per-session application contexts. The CLIENT_IDENTIFIER is also viewable in the user session and accessible in the USERENV naming context. The use of a CLIENT_IDENTIFIER thus functions as an application user proxy, since the CLIENT_IDENTIFIER can be used to capture the 'application username.' The ability to pass a CLIENT_IDENTIFIER to the database for use with global application context is supported in OCI, thick JDBC, and thin JDBC. For OCI-based connections, a change in CLIENT_IDENTIFIER is automatically piggybacked on the next OCI call, for additional performance benets. Application user proxy authentication can be used with global application context for additional exibility and high performance in building applications. For example, suppose a web-based application that provides information to business partners has three types of users: gold partner, silver partner, and bronze partner, representing different levels of information available. Instead of each user having his own session with individual application contexts set up, the application could set up global application contexts for gold partner, silver partner, or bronze partner and use the client identier to point the session at the correct context, in order to retrieve the appropriate type of data. The application need only initialize the three global contexts once, and use the client identier to access the correct application context to limit data access. This provides performance improvements through session reuse, and through accessing global application contexts set up once, instead of having to initialize application contexts for each session individually.
12-11
Policy Manager provides an easy-to-use interface to manage security policies and application contexts, and therefore makes VPD easier to develop. Oracle Policy Manager is the administration tool for Oracle Label Security. Oracle Label Security provides a functional, out-of-the-box VPD policy which enhances your ability to implement row-level security. It supplies an infrastructure--a label-based access control framework--whereby you can specify labels for users and data. It also enables you to create one or more custom security policies to be used for label access decisions. You can implement these policies without any knowledge of a programming language. There is no need to write additional code; in a single step you can apply a security policy to a given table. In this way, Oracle Label Security provides a straightforward, efcient way to implement ne-grained security policies using data labeling technology. Finally, the structure of Oracle Label Security labels provides a degree of granularity and exibility which cannot easily be derived from the application data alone. Oracle Label Security is thus a generic solution which can be used in many different circumstances. To create VPD policies, users must provide the schema name, table (or view) name, policy name, the function name that generates the predicate, and the statement types to which the policy applies (that is, SELECT, INSERT, UPDATE, DELETE). Oracle Policy Manager then executes the function DBMS_RLS.ADD_POLICY. You create an application context by providing the name of the context and the package that implements the context.
See Also:
Task 1: Create a PL/SQL Package that Sets the Context for Your Application Task 2: Create a Unique Context and Associate It with the PL/SQL Package Task 3: Set the Context Before the User Retrieves Data Task 4. Use the Context in a Policy Function
Task 1: Create a PL/SQL Package that Sets the Context for Your Application
Begin by creating a PL/SQL package with functions that set the context for your application. This section presents an example for creating the PL/SQL package, followed by a discussion of SYS_CONTEXT syntax and behavior.
Note: A login trigger can be used because the users context
(information such as EMPNO, GROUP, MANAGER) should be set before the user accesses any data.
12-13
This function returns the value of attribute as dened in the package currently associated with the context namespace. It is evaluated once for each statement execution, and is treated like a constant during type checking for optimization. You can use the pre-dened namespace USERENV to access primitive contexts such as userid and NLS parameters.
If you try to execute SYS_CONTEXT in a parallel query environment, you will receive a query error. See Using SYS_CONTEXT in a Parallel Query on page 12-15.
Note:
the USERENV Namespace" on page 12-3 Oracle9i SQL Reference for details about attributes Using Dynamic SQL with SYS_CONTEXT
Note: This feature is applicable when COMPATIBLE is set to
During a session in which you expect a change in policy between executions of a given query, that query must use dynamic SQL. You must use dynamic SQL because static SQL and dynamic SQL parse statements differently.
s
Static SQL statements are parsed at compile time; for performance reasons, they are not reparsed at execution. Dynamic SQL statements are parsed every time they are executed.
Consider a situation in which policy A is in force when you compile a SQL statementand then you switch to policy B and execute the statement. With static SQL, policy A remains in force: the statement is parsed at compile time and not reparsed upon execution. With dynamic SQL, however, the statement is parsed upon execution, and so the switch to policy B is carried through.
The policy "Employee name matches database user name" is represented in the form of a SQL predicate: the predicate is basically a policy. If the predicate changes, the statement must be reparsed in order to produce the correct result.
Using SYS_CONTEXT in a Parallel Query If SYS_CONTEXT is used inside a SQL function which is embedded in a parallel query, the function cannot pick up the application context. This is true because the application context exists only in the user session. To use these features in combination, you must call SYS_CONTEXT directly from the query. Consider a user-dened function within a SQL statement, which sets the users ID to 5:
CREATE FUNC proc1 AS RETURN NUMBER; BEGIN IF SYS_CONTEXT (hr, id) = 5 THEN RETURN 1; ELSE RETURN 2; END END;
If this statement is run as a single query (that is, if one process is used to run the entire query), there will be no problem. However, if this statement is run as a parallel query, the parallel execution servers (query slave processes) do not have access to the user session which contains the application context information. The query will not produce the expected results. By contrast, if you use the SYS_CONTEXT function within a query, there is no problem. For example,
SELECT * FROM EMP WHERE SYS_CONTEXT (hr, id) = 5;
In this way, it works like a bind variable: the query coordinator can access the application context information and pass it on to the parallel execution servers.
12-15
Versioning in Application Context When you execute a statement, Oracle9i takes a snapshot of the entire application context being set up by SYS_CONTEXT. Within the duration of a query, the context remains the same for all fetches of the query. If you (or a function) attempt to change the context within a query, the change will not take effect in the current query. In this way, SYS_CONTEXT enables you to store variables in a session.
Task 2: Create a Unique Context and Associate It with the PL/SQL Package
To perform this task, use the CREATE CONTEXT statement. Each context must have a unique attribute and belong to a namespace. That is, context names must be unique within the database, not just within a schema. Contexts are always owned by the schema SYS. For example:
CREATE CONTEXT order_entry USING oe_context;
where order_entry is the context namespace, and oe_context is the trusted package that can set attributes in the context namespace. After you have created the context, you can set or reset the context attributes by using the DBMS_SESSION.SET_CONTEXT package. The values of the attributes you set remain either until you reset them, or until the user ends the session. You can only set the context attributes inside the trusted procedure you named in the CREATE CONTEXT statement. This prevents a malicious user from changing context attributes without proper attribute validation. Alternatively, you can use the Oracle Policy Manager graphical user interface to create a context and associate it with a PL/SQL package. Oracle Policy Manager, accessed from Oracle Enterprise Manager, enables you to apply policies to database objects and create application contexts. It also can be used to create and manage Oracle Label Security policies.
Example 1: Implementing the Policy Example 2: Controlling User Access by Way of an Application Example 3: Event Triggers, Application Context, Fine-Grained Access Control, and Encapsulation of Privileges
Step 1. Create a PL/SQL Package Which Sets the Context for the Application Step 2. Create an Application Context Step 3. Access the Application Context Inside the Package Step 4. Create the New Security Policy
The procedure in this example assumes a one-to-one relationship between users and customers. It nds the users customer number (Cust_num), and caches the customer number in the application context. You can later refer to the cust_num attribute of your order entry context (order_entry_ctx) inside the security policy function. Note that you could use a login trigger to set the initial context.
12-17
Step 1. Create a PL/SQL Package Which Sets the Context for the Application Create the package as follows:
CREATE OR REPLACE PACKAGE apps.oe_ctx AS PROCEDURE set_cust_num ; END; CREATE OR REPLACE PACKAGE BODY apps.oe_ctx AS PROCEDURE set_cust_num IS custnum NUMBER; BEGIN SELECT cust_no INTO custnum FROM customers WHERE username = SYS_CONTEXT(USERENV, session_user); /* SET cust_num attribute in order_entry context */ DBMS_SESSION.SET_CONTEXT(order_entry, cust_num, custnum); DBMS_SESSION.SET_CONTEXT(order_entry, cust_num, custnum); END set_cust_num; END;
You can access predened attributessuch as session userby using SYS_CONTEXT(userenv, session_primitive). For more information, see Oracle9i SQL Reference Step 2. Create an Application Context Create an application context by entering:
CREATE CONTEXT Order_entry USING Apps.Oe_ctx;
Alternatively, you can use Oracle Policy Manager to create an application context. Step 3. Access the Application Context Inside the Package Access the application context inside the package that implements the security policy on the database object.
Note: You may need to set up the following data structures for
The package body appends a dynamic predicate to SELECT statements on the ORDERS_TAB table. This predicate limits the orders returned to those of the users customer number by accessing the cust_num context attribute, instead of a subquery to the customers table.
CREATE OR REPLACE PACKAGE BODY Oe_security AS
/* limits select statements based on customer number: */ FUNCTION Custnum_sec (D1 VARCHAR2, D2 VARCHAR2) RETURN VARCHAR2 IS D_predicate VARCHAR2 (2000) BEGIN D_predicate = cust_no = SYS_CONTEXT("order_entry", "cust_num"); RETURN D_predicate; END Custnum_sec; END Oe_security;
Step 4. Create the New Security Policy Create the policy as follows:
Note: You may need to set up the following data structures for
This statement adds a policy named OE_POLICY to the ORDERS_TAB table for viewing in schema SCOTT. The SECUSR.OE_SECURITY.CUSTNUM_SEC function implements the policy, is stored in the SECUSR schema, and applies to SELECT statements only.
12-19
Now, any select statement by a customer on the ORDERS_TAB table automatically returns only that customers orders. In other words, the dynamic predicate modies the users statement from this:
SELECT * FROM Orders_tab;
to this:
SELECT * FROM Orders_tab WHERE Custno = SYS_CONTEXT(order_entry,cust_num);
In reality, you might have several predicates based on a users position. For example, a sales representative would be able to see records only for his customers, and an order entry clerk would be able to see any customer order. You could expand the custnum_sec function to return different predicates based on the users position context value. The use of application context in a ne-grained access control package effectively gives you a bind variable in a parsed statement. For example:
SELECT * FROM Orders_tab WHERE Custno = SYS_CONTEXT(order_entry, cust_num)
This is fully parsed and optimized, but the evaluation of the users CUST_NUM attribute value for the ORDER_ENTRY context takes place at execution. This means that you get the benet of an optimized statement which executes differently for each user who executes the statement.
Note: You can improve the performance of the function in this
example even more by indexing CUST_NO. You could set your context attributes based on data from a database table or tables, or from a directory server using LDAP (Lightweight Directory Access Protocol).
application context within the dynamically generated predicate, with "How Fine-Grained Access Control Works" on page 12-43, which uses a subquery in the predicate Chapter 15, "Using Triggers"
Step 1. Create a PL/SQL Package to Set the Context Step 2. Create the Context and Associate It with the Package Step 3. Create the Initialization Script for the Application
In this example, assume that the application context for the Human Resources application is assigned to the HR_CTX namespace. Step 1. Create a PL/SQL Package to Set the Context Create a PL/SQL package with a number of functions that set the context for the application
Note: You may need to set up the following data structures for
12-21
BEGIN /* validate organization ID */ /* validate_org_id(orgid); /* /* set org_id attribute under namespace hr_ctx */ DBMS_SESSION.SET_CONTEXT(hr_ctx, org_id, orgid); END set_org_id; /* more functions to set other attributes for the HR application */ END hr_sec_ctx;
Step 2. Create the Context and Associate It with the Package For example:
CREATE CONTEXT Hr_ctx USING Apps.Hr_sec_ctx;
Step 3. Create the Initialization Script for the Application Suppose that the execute privilege on the package HR_SEC_CTX has been granted to the schema running the application. Part of the script will make calls to set various attributes of the HR_CTX context. Here, we do not show how the context is determined. Normally, it is based on the primitive context or other derived context.
APPS.HR_SEC_CTX.SET_RESP_ID(1); APPS.HR_SEC_CTX.SET_ORG_ID(101);
The SYS_CONTEXT function can be used for data access control based on this application context. For example, the base table HR_ORGANIZATION_UNIT can be secured by a view that restricts access to rows based on attribute ORG_ID:
Note: You may need to set up data structures for certain examples
to work:
CREATE TABLE hr_organization_unit (organization_id NUMBER);
Example 3: Event Triggers, Application Context, Fine-Grained Access Control, and Encapsulation of Privileges
This example illustrates use of the following security features in Oracle9i:
Event triggers Application context Fine-grained access control Encapsulation of privileges in stored procedures
In this example, we associate a security policy with the table called DIRECTORY which has the following columns:
Column Description
identication number for each employee employee identication number for the manager of each employee position of the employee in the corporate hierarchy
Note: You may need to set up the following data structures for
The security policy associated with this table has two elements:
s
All users can nd the MGRID for a specic EMPNO. To implement this, we create a deners right package in the Human Resources schema (HR) to perform SELECT on the table. Managers can update the positions in the corporate hierarchy of only their direct subordinates. To do this they must use only the designated application. You can implement this as follows:
12-23
* * *
Dene ne-grained access policies on the table based on EMPNO and application context. Set EMPNO by using a logon trigger. Set the application context by using the designated package for processing the updates (event triggers and application context).
PUBLIC, because ne-grained access control prevents an unauthorized user from wrongly modifying a given row.
CONNECT system/manager AS sysdba GRANT CONNECT,RESOURCE,UNLIMITED TABLESPACE,CREATE ANY CONTEXT, CREATE PROCEDURE, CREATE ANY TRIGGER TO HR IDENTIFIED BY HR; CONNECT hr/hr; CREATE TABLE Directory (Empno NUMBER(4) NOT NULL, Mgrno NUMBER(4) NOT NULL, Rank NUMBER(7,2) NOT NULL); CREATE TABLE Payroll (Empno NUMBER(4) NOT NULL, Name VARCHAR(30) NOT NULL );
/* seed the INSERT INTO INSERT INTO INSERT INTO INSERT INTO
tables with a couple of managers: */ Directory VALUES (1, 1, 1.0); Payroll VALUES (1, 'KING'); Directory VALUES (2, 1, 5); Payroll VALUES (2, 'CLARK');
/* Create the sequence number for EMPNO: */ CREATE SEQUENCE Empno_seq START WITH 5; /* Create the sequence number for RANK: */ CREATE SEQUENCE Rank_seq START WITH 100;
CREATE OR REPLACE CONTEXT Hr_app USING Hr.Hr0_pck; CREATE OR REPLACE CONTEXT Hr_sec USING Hr.Hr1_pck; CREATE or REPLACE PACKAGE Hr0_pck IS PROCEDURE adjustrankby1(Empno NUMBER); END; CREATE or REPLACE PACKAGE BODY Hr0_pck IS /* raise the rank of the empno by 1: */
/*Set context to indicate application state */ DBMS_SESSION.SET_CONTEXT('hr_app','adjstate',1); /* Now we can issue DML statement: */ Stmt := 'UPDATE SET Rank := Rank +1 FROM Directory d WHERE d.Empno = ' || Empno; EXECUTE IMMEDIATE STMT; /* Re-set application state: */ DBMS_SESSION.SET_CONTEXT('hr_app','adjstate',0); END; END;
CREATE or REPLACE PACKAGE hr1_pck IS PROCEDURE setid; END; / /* Based on userid, find EMPNO, and set it in application context */ CREATE or REPLACE PACKAGE BODY Hr1_pck IS PROCEDURE setid IS id NUMBER; BEGIN SELECT Empno INTO id FROM Payroll WHERE Name = SYS_CONTEXT('userenv','session_user') ; DBMS_SESSION.SET_CONTEXT('hr_sec','empno',id); DBMS_SESSION.SET_CONTEXT('hr_sec','appid',id); EXCEPTION /* For purposes of demonstration insert into payroll table / so that user can continue on and run example. */ WHEN NO_DATA_FOUND THEN INSERT INTO Payroll (Empno, Name) VALUES (Empno_seq.NEXTVAL, SYS_CONTEXT('userenv','session_user')); INSERT INTO Directory (Empno, Mgrno, Rank) VALUES (Empno_seq.CURRVAL, 2, Rank_seq.NEXTVAL); SELECT Empno INTO id FROM Payroll WHERE Name = sys_context('userenv','session_user') ; DBMS_SESSION.SET_CONTEXT('hr_sec','empno',id); DBMS_SESSION.SET_CONTEXT('hr_sec','appid',id); WHEN OTHERS THEN NULL;
12-25
/* If this is to be fired via a "logon" trigger, / you need to handle exceptions if you want the user to continue / logging into the database. */ END; END;
GRANT EXECUTE ON Hr1_pck TO public; CONNECT system/manager AS sysdba CREATE OR REPLACE TRIGGER Databasetrigger AFTER LOGON ON DATABASE BEGIN hr.Hr1_pck.Setid; END;
/* Creates the package for finding the MGRID for a particular EMPNO using definer's right (encapsulated privileges). Note that users are granted EXECUTE privileges only on this package, and not on the table (DIRECTORY) it is querying. */
CREATE or REPLACE PACKAGE hr2_pck IS FUNCTION Findmgr(Empno NUMBER) RETURN NUMBER; END; CREATE or REPLACE PACKAGE BODY hr2_pck IS /* insert a new employee record: */ FUNCTION findmgr(empno number) RETURN NUMBER IS Mgrid NUMBER; BEGIN SELECT mgrno INTO mgrid FROM directory WHERE mgrid = empno; RETURN mgrid; END; END; CREATE or REPLACE FUNCTION secure_updates(ns varchar2,na varchar2) RETURN VARCHAR2 IS Results VARCHAR2(100); BEGIN /* Only allow updates when designated application has set the session state to indicate we are inside it. */ IF (sys_context('hr_sec','adjstate') = 1) THEN results := 'mgr = SYS_CONTEXT("hr_sec","empno")';
12-27
are exposed in package oracle.security.rdbms.appctx. This API provides a centralized location to store the users application context. These classes are more fully described in Oracle9i Supplied Java Packages Reference. Related information can also be found in Oracle9i Supplied PL/SQL Packages and Types Reference. FA
The middle-tier application server can use SET_CONTEXT to set application context for a specic client ID. Then, when assigning a database connection to process the client request, the application server needs to issue a SET_IDENTIFIER to denote the ID of the application session. From then on, every time the client invokes SYS_CONTEXT, only the context that was associated with the set identier is returned. In other words, the application server uses SET_IDENTIFIER to associate the database session with a particular user or a group. Then, the CLIENT_IDENTIFIER is an attribute of the session and can be viewed in session information. Also, CLIENT_IDENTIFIER is the key to accessing the global application context. For example, suppose a web-based application that provides information to business partners has three types of users: gold partner, silver partner, and bronze partner. These users represent different levels of available information. Instead of each user having their own setup session with application contexts, the application could set up global application contexts for gold partner, silver partner, and bronze partner. Afterwards, one can do the following:
s
Use SET_IDENTIFIER to set a particular session to gold partner, silver partner, or bronze partner.
Associate the session with the correct global application context, in order to retrieve the appropriate data for gold, silver, and bronze partners, respectively.
The application need only initialize the three global contexts once, and use CLIENT_IDENTIFIER to access the correct application context to limit data access. This provides performance improvements through session reuse, and through accessing global application contexts setup once, instead of having to initialize application contexts for each session.
Consider an application server that has assigned the client identier 12345 to client SCOTT. It then issues the following statement to indicate that, for this client identier, there is an application context RESPONSIBILITY with a value of 13 in the HR namespace.
DBMS_SESSION.SET_CONTEXT( HR, RESPONSIBILITY , 13, SCOTT, 12345 );
Then, for each client session using APPSMGR to establish a connection to database, the following command should be issued when client SCOTT is assigned to a new database session to indicate identity:
DBMS_SESSION.SET_IDENTIFIER(12345);
3.
Within the database session, when there is a SYS_CONTEXT(HR,RESPONSIBILITY) call, the database engine will match the client identier 12345 to the global context, and return the value 13. When exiting this database session, middle tier can clear the client identier by issuing:
DBMS_SESSION.CLEAR_IDENTIFIER( );
4.
After the client identier in a session is clear, it takes on a NULL value, implying that any subsequent SYS_CONTEXT call will only retrieve application context with a
12-29
NULL client identier, until the client identier is set again using the SET_IDENTIFIER interface.
Note: Versioning is not available for application context accessed
globally. This will return a point in time SYS_CONTEXT value. Since multiple client sessions could be accessing the same global application context values at any time, versioning is not possible. Simple application context is per session, and can be versioned.
2. 3. 4. 5. 6.
The HR application server (AS) starts up and establishes multiple connections to the HR database as user APPSMGR. User SCOTT logs on to the HR application server. AS authenticates SCOTT into the application. AS assigns a temporary session ID (or simply uses the application user ID), 12345, for this connection. The session ID is returned to SCOTTs browser as part of a cookie or maintained by AS. If the application generates a session ID for use as a CLIENT_IDENTIFIER, the session ID must be suitably random, and protected over the network through encryption. If the session ID is not random, then a malicious user could guess the session ID and access another user's data. If the session ID is unencrypted over the network, then a malicious user could retrieve the session ID and access the connection.
Note:
7.
AS initializes application context for this client calling the HR.INIT package, which issues:
DBMS_SESSION.SET_CONTEXT( hr, id, scott, APPSMGR, 12345 ); DBMS_SESSION.SET_CONTEXT( hr, dept, sales, APPSMGR, 12345 );
8.
AS assigns a database connection to this session, and initializes the session by issuing:
DBMS_SESSION.SET_IDENTIFIER( 12345 );
9.
All SYS_CONTEXT calls within this database session will return application context values belonging to the client session only. For example, SYS_CONTEXT(hr,id) will return the value SCOTT. the client identity:
DBMS_SESSION.CLEAR_IDENTIFIER ( );
10. When done with the session, AS can issue the following statement to clean up
Note that even if another database user (ADAMS) had logged into the database, he cannot access the global context set by AS because AS has specied that only the application with logged in user APPSMGR can see it. If AS has used the following, then any user session with client ID set to 12345 can see the global context.
DBMS_SESSION.SET_CONTEXT( hr, id, scott, NULL , 12345 ); DBMS_SESSION.SET_CONTEXT( hr, dept, sales, NULL , 12345 );
This approach enables different users to share the same context. The users, however, should be aware of the security implication of different settings of the global context. Basically, NULL in the username means that any user can access the global context. A NULL client ID in the global context means that only a session with an uninitialized client ID can access the global context. Users can query the client identier set in the session as follows:
SYS_CONTEXT(USERENV,CLIENT_IDENTIFIER)
The DBA can see which sessions have the client identier set by querying the V$SESSION views CLIENT_IDENTIFIER and USERNAME. When a user wants to see how much global context area (in bytes) is being used, she can use SYS_CONTEXT(USERENV,GLOBAL_CONTEXT_MEMORY)
See Also:
Oracle9i Supplied PL/SQL Packages and Types Reference Oracle9i JDBC Developers Guide and Reference and Oracle Call Interface Programmers Guide for client identier information
12-31
The user's title The users' organization The user's physical location
The ability to initialize application context from external sources such as LDAP helps organizations leverage existing information they have for VPD enforcement, that is centrally managed, without requiring replication or duplication of this information in database tables. This section contains these topics:
s
Obtaining Default Values from Users Obtaining Values from Other External Resources Obtaining Values for Users Not Known to the Database
context that takes default values from resources other than the designated PLSQL procedure. In addition, performance is enhanced because this feature provides an extensible interface for the OCI client to bundle more information to the server in one OCISessionBegin() call.
For remote sessions, automatic propagation of context values that are in external initialized context namespace For job queues, restoration of context values that are in externally initialized context namespace For OCI interface, a mechanism to initialize context values that are in externally initialized context namespace
Although this new type of namespace can be initialized by any client program using OCI, there are login event triggers that can verify the values. It is up to the application to interpret and trust the values of the attributes. Note that with this feature, the middle-tier server can actually initialize context values on behalf of database users. Context attributes are propagated for the remote session at initiation time, and the remote database accepts the values if the namespace is externally initialized.
12-33
enables reuse of sessions by the application merely by changing the client identier (to represent the new application user name). When a client changes the client identier, the change is piggybacked on the next OCI (or thick JDBC) call, for additional performance gains. Application user proxy (via client identier) is available in available in OCI, thick JDBC, and thin JDBC. Suppose, for example, that user Daniel connects to a Web Expense application. Daniel is not a database user, he is a typical Web Expense application user. The application sets up a global application context for a typical web user and sets DANIEL as the client identier. Daniel completes his Web Expense form and exits the application. Ajit now connects to the Web Expense application. Instead of setting up a new session for Ajit, the application reuses the session that currently exists for Daniel, merely by changing the client identier to AJIT. This avoids both the overhead of setting up a new connection to the database, and the overhead of initializing a new application context. Note that the client identier can be anything the application wishes to base access control upon; it need not be an application username. Another way in which the client identier can be used for applications whose users are not database users, is to use the client identier as a type of group or role mechanism. For example, suppose a Marketing application has three types of users: standard partners, silver partners, and gold partners. The application could use the global application context feature to set up three types of contexts (standard, silver, and gold). The application then determines which type of partner a user is, and, passes the client identier to the database for a session. The client identier (standard, silver, or gold) here acts like a pointer to the correct application context. There may be multiple sessions that are silver, for example, and yet they all share the same application context.
See Also:
Oracle9i JDBC Developers Guide and Reference Oracle Call Interface Programmers Guide
Application Context Utilizing LDAP How Globally Initialized Application Context Works Example: Initializing Application Context Globally
12-35
Figure 121 Location of Application Context in LDAP Directory Information Tree (DIT)
cn=OracleContext
cn=Products
cn=OracleDBSecurity
cn=OracleDefaultDomain
cn=MyDomain
cn=OracleDBAppContent
cn=Enterprise Role
cn=Mapping
cn=HR
cn=Title
cn=Project
cn=Manager
cn=Promotion
dn: cn=Manager, cn=Title, cn=HR, cn=OracleDBAppContext, cn=MyDomain, cn=Products, cn=OracleContext, ou=Americas, o=Oracle, c=US cn: Manager objectclass: top objectclass: groupOfUniqueNames objectclass: orclDBApplicationContext uniquemember: cn=user1, ou=Americas, o=Oracle, l=Redwoodshores, st=CA, c=US
2.
Create and add new entries in the LDAP directory. An example of the entries added to the LDAP directory follows. These entries create an attribute name Title with attribute value Manager for the application (namespace) HR, and assign usernames user1 and user2.
dn: cn=OracleDBAppContext,cn=myDomain,cn=OracleDBSecurity,cn=Products,cn=OracleC ontext,ou=Americas,o=oracle,c=US changetype: add cn: OracleDBAppContext objectclass: top objectclass: orclContainer dn: cn=HR,cn=OracleDBAppContext,cn=myDomain,cn=OracleDBSecurity,cn=Products,cn=O racleContext,ou=Americas,o=oracle,c=US changetype: add cn: HR objectclass: top objectclass: orclContainer
12-37
dn: cn=Title,cn=HR,cn=OracleDBAppContext,cn=myDomain,cn=OracleDBSecurity,cn=Prod ucts,cn=OracleContext,ou=Americas,o=oracle,c=US changetype: add cn: Title objectclass: top objectclass: orclContainer dn: cn=Manager,cn=Title,cn=HR,cn=OracleDBAppContext,cn=myDomain,cn=OracleDBSecur ity,cn=Products,cn=OracleContext,ou=Americas,o=oracle,c=US cn: Manager objectclass: top objectclass: groupofuniquenames objectclass: orclDBApplicationContext uniquemember: CN=user1,OU=Americas,O=Oracle,L=Redwoodshores,ST=CA,C=US uniquemember: CN=user2,OU=Americas,O=Oracle,L=Redwoodshores,ST=CA,C=US 3.
If an LDAP inetOrgPerson object entry exists for the user, the connection will also retrieve all the attributes from inetOrgPerson and assign them to the namespace SYS_LDAP_USER_DEFAULT. The following is an example of an inetOrgPerson entry:
dn: cn=user1,ou=Americas,O=oracle,L=redwoodshores,ST=CA,C=US changetype: add objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson cn: user1 sn: One givenName: User initials: UO title: manager, product development uid: uone mail: [email protected] telephoneNumber: +1 650 123 4567 employeeNumber: 00001 employeeType: full time
4.
Connect to the database. When user1 connects to a database that belongs to domain myDomain, user1 will have his Title set to Manager. Any information related to user1 will be retrieved from the LDAP directory. The value can be obtained using the syntax
SYS_CONTEXT(namespace,attribute name)
For example:
DECLARE tmpstr1 VARCHAR2(30); tmpstr2 VARCHAR2(30); BEGIN tmpstr1 = SYS_CONTEXT(HR,TITLE); tmpstr2 = SYS_CONTEXT(SYS_LDAP_USER_DEFAULT,telephoneNumber); DBMS_OUTPUT.PUT_LINE(Title is || tmpstr1); DBMS_OUTPUT.PUT_LINE(Telephone Number is || tmpstr2); END;
12-39
Features of Fine-Grained Access Control How Fine-Grained Access Control Works How to Establish Policy Groups How to Add a Policy to a Table, View, or Synonym How to Check for Policies Applied to Statement EXEMPT ACCESS POLICY System Privilege Use of Ad Hoc Tools a Potential Security Problem
Table-, View-, or Synonym-Based Security Policies Multiple Policies for Each Table, View, or Synonym Grouping of Security Policies High Performance Default Security Policies
Security
Attaching a policy to a table, view, or synonym overcomes a potentially serious application security problem. Suppose a user is authorized to use an application, and then, drawing on the privileges associated with that application, wrongfully modies the database by using an ad hoc query tool, such as SQL*Plus. By attaching security policies to tables, views, or synonyms, ne-grained access control ensures that the same security is in force, no matter how a user accesses the data.
Simplicity
Adding the security policy to the table, view, or synonym means that you make the addition only once, rather than repeatedly adding it to each of your table-, view-, or synonym-based applications.
Flexibility
You can have one security policy for SELECT statements, another for INSERT statements, and still others for UPDATE and DELETE statements. For example, you might want to enable a Human Resources clerk to SELECT all employee records in her division, but to UPDATE only salaries for those employees in her division whose last names begin with "A" through "F".
Although you can dene a policy against a table, you cannot select that table from within the policy that was dened against the table.
Note:
12-41
High Performance
With ne-grained access control, each policy function for a given query is evaluated only once, at statement parse time. Also, the entire dynamically modied query is optimized and the parsed statement can be shared and reused. This means that rewritten queries can take advantage of Oracles high performance features, such as dictionary caching and shared cursors.
In this case, you might create a function that adds the following predicate:
Cust_no = (SELECT Custno FROM Customers WHERE Custname = SYS_CONTEXT (userenv,session_user)) 2.
12-43
3. 4.
The Oracle server calls the function you created to implement the security policy. The function dynamically modies the users statement to read:
SELECT * FROM Orders_tab WHERE Custno = ( SELECT Custno FROM Customers WHERE Custname = SYS_CONTEXT(userenv, session_user))
5.
Upon execution, the function employs the username returned by SYS_CONTEXT (userenv,session_user) to look up the corresponding customer and to limit the data returned from the ORDERS_TAB table to that customers data only.
control, see "Introduction to Application Context Accessed Globally" on page 12-27, as well as Oracle9i Supplied PL/SQL Packages and Types Reference.
The Default Policy Group: SYS_DEFAULT New Policy Groups Using Oracle Policy Manager to Establish Policy Groups How to Implement Policy Groups Validation of the Application Used to Connect
an icon for each policy group, as well as an icon for the SYS_DEFAULT policy group. By default, all policies belong to the SYS_DEFAULT policy group. Policies dened in this group for a particular table, view, or synonym will always be executed along with the policy group specied by the driving context. The SYS_DEFAULT policy group may or may not contain policies. If you attempt to drop the SYS_DEFAULT policy group, an error will be raised. If, to the SYS_DEFAULT policy group, you add policies associated with two or more objects, then each such object will have a separate SYS_DEFAULT policy group associated with it. For example, the EMP table in the SCOTT schema has one SYS_DEFAULT policy group, and the DEPT table in the SCOTT schema has a different SYS_DEFAULT policy group associated with it. These are displayed in the tree structure as follows:
SYS_DEFAULT - policy1 (SCOTT/EMP) - policy3 (SCOTT/EMP) SYS_DEFAULT - policy2 (SCOTT/DEPT)
Policy groups with identical names are supported. When you select a particular policy group, its associated schema and object name are displayed in the property sheet on the right-hand side of the screen
Note:
12-45
Consider, for example, a hosting company that hosts Benets and Financial applications, which share some database objects. Both applications are striped for hosting using a SUBSCRIBER policy in the SYS_DEFAULT policy group. Data access is partioned rst by subscriber ID, then by whether the user is accessing the Benets or Financial applications (determined by a driving context). Suppose that Company A, which uses the hosting services, wants to apply a custom policy which relates only to its own data access. You could add an additional driving context (such as COMPANY A SPECIAL) to ensure that the additional, special policy group is applied for Company A's data access only. You would not apply this under the SUBSCRIBER policy, since the policy relates only to Company A, and it is cleaner to segregate the basic hosting policy from other policies.
context.
Set up a driving context to identify the effective policy group. Add policies to policy groups, as required.
The following example shows how to perform these tasks. Step 1: Set Up a Driving Context Begin by creating a namespace for the driving context. For example:
CREATE CONTEXT appsctx USING apps.apps_security_init;
Create the package that administers the driving context. For example:
CREATE OR REPLACE PACKAGE BODY apps.apps_security_init PROCEDURE setctx ( policy_group varchar2 ) BEGIN REM Do some checking to determine the current application. REM You can check the proxy if using the proxy authentication feature.
REM Then set the context to indicate the current application. . . . DBMS_SESSION.SET_CONTEXT(APPSCTX,ACTIVE_APPS, policy_group); END; END;
Step 2: Add a Policy to the Default Policy Group. Create a security function to return a predicate to divide the data by company.
CREATE OR REPLACE FUNCTION by_company (schema varchar2, table varchar2) RETURN VARCHAR2; BEGIN RETURN COMPANY = SYS_CONTEXT(ID,MY_COMPANY); END;
Since policies in SYS_DEFAULT are always executed (except for SYS, or users with the EXEMPT ACCESS POLICY system privilege), this security policy (named SECURITY_BY_COMPANY), will always be enforced regardless of the application running. This achieves the universal security requirement on the table: namely, that each company should see its own data, regardless of the application running. The function APPS.APPS_SECURITY_INIT.BY_COMPANY returns the predicate to make sure that you can only see your companys data.
DBMS_RLS.ADD_GROUPED_POLICY(apps,benefit,SYS_DEFAULT, security_by_company, apps,by_company);
Step 3: Add a Policy to the HR Policy Group First, create the HR group:
CREATE OR REPLACE FUNCTION hr.security_policy RETURN VARCHAR2; AS BEGIN RETURN SYS_CONTEXT(ID,TITLE) = MANAGER ; END; DBMS_RLS.CREATE_POLICY_GROUP(apps,benefit,HR);
12-47
The following adds a policy named HR_SECURITY to the HR policy group. The function HR.SECURITY_POLICY returns the predicate to enforce HRs security on the table APPS.BENEFIT:
DBMS_RLS.ADD_GROUPED_POLICYS(apps,benefit,HR, hr_security,hr,security_policy);
Step 4: Add a Policy to the FINANCE Policy Group Create the FINANCE policy:
CREATE OR REPLACE FUNCTION finance.security_policy RETURN VARCHAR2; AS BEGIN RETURN SYS_CONTEXT(ID,DEPT) = FINANCE ; END;
As a result, when the database is accessed, the application initializes the driving context after authentication. For example, with the HR application:
execute apps.security_init.setctx(HR);
The companys BENEFITS application allows more liberal access than its HR application, and
The setctx procedure (which sets the correct policy group within the driving context) does not perform any validation to determine which application is actually connecting. That is, the procedure does not check the IP address of the incoming connection (for a three-tier system), or, even better, the proxy_user attribute of the user session.
In this situation, the user could pass to the driving context package an argument (BENEFITS) which would set the context to the more liberal BENEFITS policy groupeven though this user will, in fact, access the HR application. In this way the user can bypass the intended, more restrictive security policy simply because the package does inadequate validation. If, by contrast, you implement proxy authentication with VPD, you can determine the identity of the middle tier (and thus, the application) which is actually connecting to the database on a user's behalf. In this way, the correct, per-application policy will be applied to mediate data access. For example, a developer using the proxy authentication feature could determine that the application (that is, the middle tier) connecting to the database is HRAPPSERVER. The package which implements the driving context can thus verify that the proxy_user in the user session is HRAPPSERVER before setting the driving context to use the HR policy group, or can disallow access if proxy_user is not HRAPPSERVER. In this case, when the following query is executed
SELECT * FROM APPS.BENEFIT;
Oracle picks up policies from the default policy group (SYS_DEFAULT) and active namespace HR. The query is internally rewritten as follows:
SELECT * FROM APPS.BENEFIT WHERE COMPANY = SYS_CONTEXT(ID,MY_COMPANY) and SYS_CONTEXT(ID,TITLE) = MANAGER;
12-49
DELETE), and additional information. The package includes the following procedures:
Table 122 DBMS_RLS Procedures
Procedure DBMS_RLS.ADD_POLICY DBMS_RLS.DROP_POLICY DBMS_RLS.REFRESH_POLICY Purpose Use this procedure to add a policy to a table, view, or synonym. Use this procedure to drop a policy from a table, view, or synonym. Use this procedure to force a reparse of open cursors associated with a policy, so that a new policy or change to a policy can take effect immediately. Use this procedure to enable (or disable) a policy you previously added to a table, view, or synonym. Use this procedure to create a policy group. Use this procedure to add a policy to the specied policy group. Use this procedure to add the context for the active application. Use this procedure to drop a policy group. Use this procedure to drop a policy which is a member of the specied group. Use this procedure to drop the context for the application. Use this procedure to enable a policy within a group.
DBMS_RLS.ENABLE_POLICY
DBMS_RLS.REFRESH_GROUPED_POLICY Use this procedure to reparse the SQL statements associated with a refreshed policy.
See Also:
Alternatively, you can use Oracle Policy Manager to administer security policies.
DBMS_RLS.REFRESH_GROUPED_POLICY VARCHAR2(4096)
12-51
privilege to other users, and thus propagate the ability to bypass ne-grained access control.
Automatic Reparse
Note: This feature is applicable when COMPATIBLE is set to 9.0.1.
Starting from 9i, queries against Fine Grained Access enabled objects always execute the policy function to make sure most up to date predicate is used for each policy. For example, in case of the time based policy function, in which queries are only allowed between 8am-5pm, an execute of a cursor that is parsed at noon would result in an execution of the policy function at the execution time to make sure policy function is consulted again for the query. There are only two exceptions to this rule. One is to specify STATIC_POLICY=TRUE when adding the policy to indicate that the policy function always returns the same predicate. Another one is for users whose security policies do not return different predicate within a database session, the init.ora parameter _dynamic_rls_policies can be set to FALSE to reduce the execution overhead. For deployment environments where latest application context value is always the desired value, init.ora parameter _app_ctx_vers can be set to FALSE to reduce overhead of application context scoping. By default, it is TRUE, and changes of value within a SQL is not visible. This default may change in the future, thus developers should be careful not to allow changes of application context values within a SQL statement using a user dened function, just like other Write No Database State requirements of user dened function executed within a SQL. In general, users should not depend on order of execution in a SQL statement as this could yield inconsistent result depending on query plans. Note that these two parameters may be deprecated in coming releases when there is new functionality to replace them.
See Also:
page 12-14
Fine-Grained Auditing
Fine-Grained Auditing
This section describes ne-grained auditing in the context of Oracle9i auditing capabilities. It contains the following sections:
s
Introduction to Standard Auditing and Fine-Grained auditing Standard Oracle9i Auditing Techniques Fine-Grained Auditing Techniques
12-53
Fine-Grained Auditing
You can use triggers to record customized information that is not automatically included in audit records. In this way, you can further design your own audit auditing conditions and audit record contents. For example, you could dene a trigger on the EMP table to generate an audit record whenever an employee's salary is increased by more than 10 percent. This can include selected information, such as before and after values of SALARY:
CREATE TRIGGER audit_emp_salaries AFTER INSERT OR DELETE OR UPDATE ON employee_salaries for each row begin if (:new.salary> :old.salary * 1.10) then insert into emp_salary_audit values ( :employee_no, :old.salary, :new.salary, user, sysdate); endif; end;
Furthermore, you can use event triggers to enable auditing options for specic users on login, and disable them upon logoff. In some cases, businesses may actually need to capture the statement executed as well as the result set from a query. Fine-grained auditing provides an extensible auditing mechanism that supports denition of key conditions for granular audit, as well as an event handler to actively alert administrators to misuse of data access rights. Oracle9i also gives you the option of sending audit records to the database audit trail or your operating system's audit trail, when the operating system is capable of receiving them. The audit trail for database administrators, for example, is typically written to a secure location in the operating system. Writing audit trails to the OS provides a way for a separate auditor who is root on the OS to hold all DBAs (who don't have root access) accountable for their actions. These options, added to the broad selection of audit options and customizable triggers or stored procedures, give you the exibility to implement an auditing scheme that suits your specic business needs.
Fine-Grained Auditing
12-55
Fine-Grained Auditing
Then, either of the following SQL statements will cause the database to log an audit event record.
SELECT count(*) FROM hr.emp WHERE dept = SALES and salary > 10000000;
or
SELECT salary FROM hr.emp WHERE dept = SALES;
With all the relevant information available, and a trigger-like mechanism to use, the administrator can dene what to record and how to process the audit event. Consider what happens when the following commands are issued. After the fetch of the rst interested row, the event is recorded, and the audit function SEC.LOG_ID is executed. The audit event record generated is stored in DBA_FGA_AUDIT_TRAIL, which has reserved columns for recording SQL text, policy name, and other information.
/* create audit event handler */ CREATE PROCEDURE sec.log_id (schema varchar2, table varchar2, policy varchar2) AS BEGIN UTIL_ALERT_PAGER(schema, table, policy); -- send an alert note to my pager END; /* add the policy */ DBMS_FGA.ADD_POLICY( object_schema => hr, object_name => emp, policy_name => chk_hr_emp, audit_condition => dept = SALES , audit_column => salary, handler_schema => sec, handler_module => log_id, enable => TRUE);
optimization. For query, using rule-based optimization, audit will check before applying row ltering, which could result in an unnecessary audit event trigger.
Use of Ad Hoc Tools a Potential Security Problem Restricting Database Roles from SQL*Plus Users
The Vacation application has a corresponding VACATION role. The VACATION role includes the privileges to issue SELECT, INSERT, UPDATE, and DELETE statements against the EMP_TAB table. The Vacation application controls the use of privileges obtained through the VACATION role.
Now, consider a user who has been granted the VACATION role. Suppose that, instead of using the Vacation application, the user executes SQL*Plus. At this point, the user is restricted only by the privileges granted to him explicitly or through roles, including the VACATION role. Because SQL*Plus is an ad hoc query tool, the user is not restricted to a set of predened actions, as with designed database applications. The user can query or modify data in the EMP_TAB table as he or she chooses.
12-57
Limiting Roles Through PRODUCT_USER_PROFILE Using Stored Procedures to Encapsulate Business Logic Using Virtual Private Database for Highest Security Virtual Private Database and Oracle Label Security
Disallow use of the CLERK and MANAGER roles with SQL*Plus Disallow use of SET ROLE with SQL*Plus
Suppose user Jane connects to the database using SQL*Plus. Jane has the CLERK, MANAGER, and ANALYST roles. As a result of the above entry in PRODUCT_USER_PROFILE, Jane is only able to exercise her ANALYST role with SQL*Plus. Also, when Jane attempts to issue a SET ROLE statement, she is explicitly prevented from doing so because of the entry in the PRODUCT_USER_PROFILE table prohibiting use of SET ROLE. Use of the PRODUCT_USER_PROFILE table does not completely guarantee security, for multiple reasons. In the above example, while SET ROLE is disallowed with SQL*Plus, if Jane had other privileges granted to her directly, she could exercise these using SQL*Plus.
.
See Also: SQL*Plus Users Guide and Reference for more information about the PRODUCT_USER_PROFILE table
12-59
Application context enables you to securely access the attributes on which you base your security policies. For example, users with the position attribute of manager would have a different security policy than users with the position attribute of employee. Consider an HR clerk who is only allowed to see employee records in the Aircraft Division. When the user initiates the query
SELECT * FROM emp;
the function implementing the security policy returns the predicate division = AIRCRAFT, and the database transparently rewrites the query. The query actually executed becomes:
SELECT * FROM emp WHERE division = AIRCRAFT;
The security policy is applied within the database itself, rather than within an application. This means that use of a different application will not bypass the security policy. Security can thus be built once, in the database, instead of being reimplemented in multiple applications. Virtual Private Database therefore provides far stronger security than application-based security, at a lower cost of ownership. It may be desirable to enforce different security policies depending on which application is accessing data. Consider a situation in which two applications, Order Entry and Inventory, both access the ORDERS table. You may want to have the Inventory application apply to the table a policy which limits access based on type of product. At the same time, you may want to have the Order Entry application apply to the same table a policy which limits access based on customer number. In this case, you must partition the use of ne-grained access by application. Otherwise, both policies would be automatically ANDed togetherwhich is not the desired result. You can specify one or more policy groups, and a driving application context that determines which policy group is in effect for a given transaction. You can also designate default policies which always apply to data access. In a hosted application, for example, data access should always be limited by subscriber ID.
policies cannot be applied to objects in schema SYS. As a consequence, the SYS user and users making a DBA-privileged connection to the database (for example, CONNECT/AS SYSDBA) do not have VPD or Oracle Label Security policies applied to their actions. Database administrators need to be able to administer the database. It would not be acceptable to export part of a table due to a VPD policy being applied. SYSDBA actions are auditable, however, by enabling such auditing upon installation and specifying that this audit trail be stored in a secure location in the operating system. Database users who are granted the Oracle9i EXEMPT ACCESS POLICY privilege, directly or through a database role, are exempt from Virtual Private Database and Oracle Label Security enforcement. The users are exempt from Virtual Private Database and Oracle Label Security enforcement regardless of the export mode, application, or utility used to extract data from the database. EXEMPT ACCESS POLICY privilege is a powerful privilege and should be carefully managed. It is usually inadvisable to grant this privilege WITH ADMIN OPTION because very few users should have this exemption.
Note: The EXEMPT ACCESS POLICY privilege does not affect the enforcement of object privileges such as SELECT, INSERT, UPDATE, and DELETE. These privileges are enforced even if a user has been granted the EXEMPT ACCESS POLICY privilege.
12-61
13
Proxy Authentication
This chapter provides information about proxy authentication in a multi-tier system. Topics in this chapter are presented in the following sections:
s
Advantages of Proxy Authentication Security Challenges of Three-tier Computing Oracle9i Proxy Authentication Solutions
Proxy Authentication
13-1
Application servers and web servers enable users to access data stored in legacy applications. Users like using a familiar, easy-to-use browser interface. Organizations can separate application logic from data storage, partitioning the former in application servers and the latter in databases. Organizations can also lower their cost of computing by replacing many "fat clients" with a number of "thin clients" and an application server.
A limited trust model, by controlling the users on whose behalf middle tiers can connect, and the roles the middle tiers can assume for the user Scalability, by supporting lightweight user sessions through OCI and thick JDBC, and eliminating the overhead of re-authenticating clients Accountability, by preserving the identity of the real user through to the database, and enabling auditing of actions taken on behalf of the real user Flexibility, by supporting environments in which users are known to the database, and in which users are merely "application users" of which the database has no awareness
Note: Oracle9i supports the above functionality in three tiers only; it does not support functionality across multiple middle tiers.
13-2
Who Is the Real User? Does the Middle Tier Have Too Much Privilege? How to Audit? Whom to Audit? Can the User Be Re-Authenticated to the Database?
Proxy Authentication
13-3
whereas a user connecting to a web server or application server within the enterprise might be able to exercise all privileges she is otherwise entitled to have.
Client to Middle Tier Authentication Middle Tier to Database Authentication Client Re-Authentication Through Middle Tier to Database
13-4
Proxy Authentication
13-5
In short, organizations deploying three-tier systems require exibility as regards re-authentication of the client. In some cases, they cannot re-authenticate the client; in other cases, they may choose whether or not to re-authenticate the client.
Passing Through the Identity of the Real User Limiting the Privilege of the Middle Tier Re-authenticating the Real User Auditing Actions Taken on Behalf of the Real User Support for Application User Models
The client authenticates to the middle tier, using whatever form of authentication the middle tier will accept. For example, the client could authenticate to the middle tier using a username/password, or an X.509 certicate by means of SSL.
13-6
2.
The middle tier creating the lightweight sessions must be a database user, rather than an enterprise user. The middle tier authenticates itself to Oracle9i, using whatever form of authentication Oracle9i will accept. This could be a password, or an authentication mechanism supported by Oracle Advanced Security, such as a Kerberos ticket or an X.509 certicate (SSL). The middle tier then creates one or more sessions for users using the Oracle Call Interface or thick JDBC.
s
3.
If the user is a database user, the lightweight session must, as a minimum, include the database username. If the database requires it, the session may also include a password (which the database veries against the password store in the database). The session may also include a list of database roles for the user. If the user is an enterprise user, the lightweight session may provide different information depending on how the user is authenticated. If the user authenticated to the middle tier via SSL, the middle tier can provide the DN from the user's X.509 certicate, or the certicate itself in the session. The database uses the DN to look up the user in Oracle Internet Directory. If the user is a password-authenticated enterprise user, then the middle tier must provide, as a minimum, a globally unique name for the user. The database uses this name to look up the user in Oracle Internet Directory. If the session also provides a password for the user, the database will verify the password against Oracle Internet Directory. The user's roles are automatically retrieved from Oracle Internet Directory after the session is established. The middle tier may optionally provide a list of database roles for the client, in cases where the user is a database user rather than an enterprise user. If the user is an enterprise user, then the users roles are automatically retrieved from Oracle Internet Directory after the session is established.
4.
If the user is a database user, the database veries that the middle tier is privileged to create sessions on behalf of the user, using the roles provided. The OCISessionBegin call will fail if the application server is not allowed to proxy on behalf of the client by the administrator, or if the application server is not allowed to activate the specied roles.
Proxy Authentication
13-7
applications, this means that the middle tier should not have more privileges than it needs. Oracle9i enables you to limit the middle tier such that it can connect only on behalf of certain database users, using only specic database roles. You cannot limit the ability of the middle tier to connect on behalf of enterprise users or limit the user of enterprise roles in OCI or thick JDBC lightweight connections. For example, suppose that user Sarah wants to connect to the database through a middle tier, appsrv (which is also a database user). Sarah has multiple roles, but it is desirable to restrict the middle tier to exercise only the clerk role on her behalf. A DBA could effectively grant permission for appsrv to initiate connections on behalf of Sarah using her clerk role only, using the following syntax:
ALTER USER Sarah GRANT CONNECT THROUGH appsrv WITH ROLE clerk;
By default, the middle tier cannot create connections for any client. The permission must be granted on a per-user basis. To allow appsrv to use all of the roles granted to the client Sarah, the following statement would be used:
ALTER USER sarah GRANT CONNECT THROUGH appsrv;
Each time a middle tier initiates a lightweight (OCI) or thick JDBC session for another database user, the database veries that the middle tier is privileged to connect for that user, using the role specied. You can limit the privilege of the middle tier to connect on behalf of an enterprise user by granting to the middle-tier the privilege to connect as the underlying database user. For instance, if the enterprise user is mapped to the APPUSER schema, you must at least grant to the middle tier the ability to connect on behalf of APPUSER. Otherwise, attempts to create a session for the enterprise user will fail.
13-8
.
See Also: For more information about security in three-tier
To pass over the entire certicate, the middle tier would use the following pseudo-interfaces:
OCIAttrSet(OCISession *session_handle, OCI_HTYPE_SESSION, ub1 *certificate, ub4 certificate_length, OCI_ATTR_CERTIFICATE, OCIError *error_handle);
If the type is not specied, then the server will use its default certicate type of X.509. If using proxy authentication for password-authenticated enterprise users, use the same OCI attributes as for database users authenticated by password (e.g. OCI_ ATTR_USERNAME). The database rst checks the username against the database; if
Proxy Authentication
13-9
no user is found, then the database checks the username in the directory. This username must be globally unique.
Alternatively, the DBA could enable auditing on behalf of multiple users (in this case, both Jane and Ajit) connecting through a middle tier as follows:
AUDIT SELECT TABLE BY hrappserver ON BEHALF OF ANY;
This auditing option only audits SELECT statements being initiated by hrappserver on behalf of other users. A DBA can enable separate auditing options to capture SELECTs against the bonus table from clients connecting directly to the database:
AUDIT SELECT TABLE.
For audit actions taken on behalf of the real user, you cannot audit CONNECT ON BEHALF OF DN, since the distinguished name is not known to the database. However, if the user accesses a shared schema (for example, APPUSER), then you can audit CONNECT ON BEHALF OF APPUSER.
Applications can reset the client identier and thus reuse the session for a different user, enabling high performance. For OCI-based connections, alteration of the CLIENT_IDENTIFIER is piggybacked on the other OCI calls to further enhance performance. Application user proxy is available in thin JDBC, thick JDBC, and OCI, and provides the benets of connection pooling without the overhead of separate user sessions (even lightweight ones). Application user proxy can be used with global application context for additional exibility and high performance in building applications. For example, suppose a web-based application that provides information to business partners has a notion of three types of users: gold partner, silver partner, or bronze partner representing the different levels of information available. It is not important to the application that users be known to the database, but it needs to limit data access based on contexts representing gold partner, silver partner, or bronze partner respectively. That is, instead of each user having his own sessionwith the individual application context set upthe application could set up global application contexts for gold partner, silver partner, or bronze partner and use the client identier to point the session at the correct context, in order to retrieve the appropriate type of data. The application need only initialize the three global contexts, and use the client identier to access the correct application context to limit data access. This provides performance improvements through session reuse, and through accessing global application contexts set up once, instead of having to initialize application contexts for each session individually.
See Also:
s
"Initializing Application Context Globally" on page 12-34 Oracle9i JDBC Developers Guide and Reference
14
Data Encryption Using DBMS_OBFUSCATION_TOOLKIT
This chapter provides a description of the data encryption package (DBMS_OBFUSCATION_TOOLKIT) that allows you to encrypt data in a database. Data encryption topics are presented in the following sections:
s
Securing Sensitive Information Principles of Data Encryption Solutions For Stored Data Encryption in Oracle9i Data Encryption Challenges Example of Data Encryption PL/SQL Program
Strong user authentication to identify users Granular access control to limit what users can see and do Auditing for accountability Network encryption to protect the condentiality of sensitive data in transmission
Encryption is an important component of several of the above solutions. For example, Secure Sockets Layer (SSL), an Internet-standard network encryption and authentication protocol, uses encryption to strongly authenticate users by means of X.509 digital certicates. SSL also uses encryption to ensure data condentiality, and cryptographic checksums to ensure data integrity. Many of these uses of encryption are relatively transparent to a user or application. For example, many browsers support SSL, and users generally do not need to do anything special to enable SSL encryption. Oracle has provided network encryption between database clients and the Oracle database since Oracle7. Oracle Advanced Security, an option to Oracle9i, provides encryption and cryptographic integrity check for any protocol supported by Oracle9i, including Net8, Java Database Connectivity (JDBC) (both thick and thin JDBC), and the Internet Intra-Orb Protocol (IIOP). Oracle Advanced Security also supports SSL for Net8, thick JDBC and IIOP connections. While encryption is not a security cure-all, it is an important tool used to address specic security threats, and will become increasingly important with the growth of e-business, especially in the area of encryption of stored data. For example, while credit card numbers are typically protected in transit to a web site using SSL, the credit card number is often stored in the clear (un-encrypted), either on the le system, where it is vulnerable to anyone who can break into the host and gain root access, or in databases. While databases can be made quite secure through proper conguration, they can also be vulnerable to host break-ins if the host is mis-congured. There have been several well-publicized break-ins, in which a hacker obtained a large list of credit card numbers by breaking into a database. Encryption of stored data thus represents a new challenge for e-businesses, and can be an important tool in dealing with specic types of security threats.
14-2
Principle 1: Encryption Does Not Solve Access Control Problems Principle 2: Encryption Does Not Protect Against a Malicious DBA Principle 3: Encrypting Everything Does Not Make Data Secure
key and part of a table with another key if users need to see all encrypted data in the table; it merely adds to the overhead of decrypting the data before users can read it. Provided that access controls are implemented well, there is little additional security provided within the database itself from encryption. Any user who has privilege to access data within the database has no more nor any less privilege as a result of encryption. Therefore, encryption should never be used to solve access control problems.
14-4
Database Administrators Guide Furthermore, the DBA function by its nature is a trusted position. Even organizations with the most sensitive datasuch as intelligence agenciesdo not typically partition the DBA function. Instead, they vet their DBAs strongly, because it is a position of trust. Periodic auditing can help to uncover inappropriate activities. Encryption of stored data must not interfere with the administration of the database; otherwise, larger security issues can result. For example, if by encrypting data you corrupt the data, youve created a security problem: data is not meaningful and may not be recoverable. Encryption can be used to mitigate the ability of a DBAor other privileged userto see data in the database. However, it is not a substitute for vetting a DBA properly, or for limiting the use of powerful system privileges. If an untrustworthy user has signicant privilege, there are multiple threats he can pose to an organization, and these may be far more signicant than viewing un-encrypted credit card numbers.
benet to encrypting this data before it is stored. Since it is not being accessed on-line, performance need not be a consideration. While Oracle9i does not provide this facility, there are vendors who can provide such encryption services. Before embarking on large-scale encryption of backup data, organizations considering this approach should thoroughly test the process. It is essential that any data which is encrypted before off-line storage, can be decrypted and re-imported successfully.
Credit card numbers National identity numbers Passwords for applications whose users are not database users
To address these needs, Oracle9i provides a PL/SQL package to encrypt and decrypt stored data. The package, DBMS_OBFUSCATION_TOOLKIT, is provided in both Standard Edition and Enterprise Edition Oracle9i. This package currently supports bulk data encryption using the Data Encryption Standard (DES) algorithm, and includes procedures to encrypt (DESEncrypt) and decrypt (DESDecrypt) using DES. The DBMS_OBFUSCATION_TOOLKIT also includes functions to encrypt and decrypt using 2-key and 3-key DES, in outer cipher block chaining mode. They require keylengths of 128 and 192 bits, respectively. The DBMS_OBFUSCATION_TOOLKIT includes a cryptographic checksumming capabilities (MD5), and the ability to generate a secure random number (GetKey). Secure random number generation is important part of cryptography; predictable keys are easily-guessed keys, and easily-guessed keys may lead to easy decryption of data. Most cryptanalysis is done by nding weak keys or poorly-stored keys, rather than through brute force analysis (cycling through all possible keys).
14-6
Key management is programmatic. That is, the application (or caller of the function) must supply the encryption key; and this means that the application developer must nd a way of storing and retrieving keys securely. The relative strengths and weaknesses of various key management techniques are discussed below. The DBMS_OBFUSCATION_TOOLKIT package, which can handle both string and raw data, requires the submission of a 64-bit key. The DES algorithm itself has an effective key length of 56-bits. The DBMS_OBFUSCATION_TOOLKIT is granted to PUBLIC by default. Oracle strongly recommends that this grant be revoked. In general, there is no reason why users should be able to encrypt stored data outside the context of an application.
See Also: Oracle9i Supplied PL/SQL Packages and Types Reference for
Encrypting Indexed Data Key Management Key Transmission Key Storage Changing Encryption Keys Binary Large Objects (BLOBS)
Key Management
To address the issue of secure cryptographic key generation, Oracle9i adds support for a secure random number generation, the GetKey procedure of the DBMS_OBFUSCATION_TOOLKIT. The GetKey procedure calls the secure random number generator (RNG) that has previously been certied against the Federal Information Processing Standard (FIPS)-140 as part of the Oracle Advanced Security FIPS-140 evaluation. Developers should not, under any circumstances use the DBMS_RANDOM package. The DBMS_RANDOM package generates
14-8
pseudo-random numbers; as RFC-1750 states, "The use of pseudo-random processes to generate secret quantities can result in pseudo-security."
Key Transmission
If the key is to be passed by the application to the database, then it must be encrypted. Otherwise, a snooper could grab the key as it is being transmitted. Use of network encryption, such as that provided by Oracle Advanced Security, will protect all data in transit from modication or interception, including cryptographic keys.
Key Storage
Key storage is one of the most important, yet difcult, aspects of encryption. To recover data encrypted with a symmetric key, the key must be accessible to the application or user seeking to decrypt the data. The key needs to be easy enough to retrieve that users can access encrypted data, without signicant performance degradation. The key needs to be secure enough not to be easily recoverable by someone who is maliciously trying to access encrypted data which he is not supposed to see. The three basic options available to a developer are:
s
Store the key in the database Store the key in the operating system Have the user manage the key
the SSN using a technique that performs some additional data transformation on the employee_number before using it to encrypt the SSN. This technique might be something as simple, for example, as XORing the employee_number with the birthdate of the employee. As additional protection, a PL/SQL package body performing encryption can be wrapped, (using the WRAP utility) which obfuscates the code. A developer could wrap a package body called KEYMANAGE as follows:
wrap iname=/mydir/keymanage.sql
A developer can subsequently have a function in the package call the DBMS_OBFUSCATION_TOOLKIT with the key contained in the wrapped package. While wrapping is not unbreakable, it makes it harder for a snooper to get the key. Because literals are still readable within the package le, the key could be split up in the package and then have the procedure to re-assemble it prior to use. Even in cases where a different key is supplied for each encrypted data value, so that the value of the key is not embedded within a package, wrapping the package that performs key management (that is, data transformation or padding) is recommended.
See Also: Oracle9i Supplied PL/SQL Packages and Types Reference for
An alternative would be to have a separate table in which to store the encryption key and to envelope the call to the keys table with a procedure. The key table can be joined to the data table using a primary key to foreign key relationship; for example, EMPLOYEE_NUMBER is the primary key in the EMPLOYEES table which stores employee information, and the encrypted SSN. EMPLOYEE_NUMBER is a foreign key to the SSN_KEYS table which stores the encryption keys for each employees SSN. The key stored in the SSN_KEYS table can also be transformed before use (i.e. through XORing), so the key itself is not stored un-encrypted. The procedure itself should be wrapped, to hide the way in which keys are transformed before use. The strengths of this approach are:
s
Users who have direct table access cannot see the sensitive data un-encrypted, nor can they retrieve the keys to decrypt the data.
Access to decrypted data can be controlled through a procedure that selects the (encrypted) data, retrieves the decryption key from the key table, and transforms it before it can be used to decrypt the data. The data transformation algorithm is hidden from casual snooping by wrapping the procedure, which obfuscates the procedure code. SELECT access to both the data table and the keys table does not guarantee that the user with this access can decrypt the data, because the key is transformed before use.
The weakness in this approach is that a user who has SELECT access to both the key table and the data table, who can derive the key transformation algorithm, can break the encryption scheme. The above approach is not bullet-proof, but it is good enough to protect against easy retrieval of sensitive information (such as credit card numbers) stored in clear text.
encrypted_string VARCHAR2(2048); decrypted_string VARCHAR2(2048); error_in_input_buffer_length EXCEPTION; PRAGMA EXCEPTION_INIT(error_in_input_buffer_length, -28232); INPUT_BUFFER_LENGTH_ERR_MSG VARCHAR2(100) := *** DES INPUT BUFFER NOT A MULTIPLE OF 8 BYTES ***; BEGIN dbms_output.put_line(> ========= BEGIN TEST =========); dbms_output.put_line(> Input String : || input_string); BEGIN dbms_obfuscation_toolkit. input_string => input_string, key_string => key_string, encrypted_string => encrypted_string ); dbms_output.put_line(> encrypted string : || encrypted_string);
dbms_obfuscation_toolkit.DESDecrypt(input_string => encrypted_string, key => raw_key, decrypted_string => decrypted_string); dbms_output.put_line(> Decrypted output : || decrypted_string); dbms_output.put_line(> ); if input_string = decrypted_string THEN dbms_output.put_line(> DES Encryption and Decryption successful); END if; EXCEPTION WHEN error_in_input_buffer_length THEN dbms_output.put_line(> || INPUT_BUFFER_LENGTH_ERR_MSG); END;
See Also:
Part IV
The Active Database
To take advantage of the reliability and performance of the database server, and to reuse program logic across all the applications in a database, you can move some of your program logic into the database itself, so that the database does cleanup operations and responds to events without the need for a separate application. This part contains the following chapters:
s
Chapter 15, "Using Triggers" Chapter 16, "Working With System Events" Chapter 17, "Using the Publish-Subscribe Model for Applications"
15
Using Triggers
Triggers are procedures that are stored in the database and implicitly run, or red, when something happens. Traditionally, triggers supported the execution of a PL/SQL block when an INSERT, UPDATE, or DELETE occurred on a table or view. Starting with Oracle8i, triggers support system and other data events on DATABASE and SCHEMA. Oracle also supports the execution of a PL/SQL or Java procedure. This chapter discusses DML triggers, INSTEAD OF triggers, and system triggers (triggers on DATABASE and SCHEMA). Topics include:
s
Designing Triggers Creating Triggers Compiling Triggers Modifying Triggers Enabling and Disabling Triggers Viewing Information About Triggers Examples of Trigger Applications Responding to System Events through Triggers
Designing Triggers
Designing Triggers
Use the following guidelines when designing your triggers:
s
Use triggers to guarantee that when a specic operation is performed, related actions are performed. Do not dene triggers that duplicate features already built into Oracle. For example, do not dene triggers to reject bad data if you can do the same checking through declarative integrity constraints. Limit the size of triggers. If the logic for your trigger requires much more than 60 lines of PL/SQL code, it is better to include most of the code in a stored procedure and call the procedure from the trigger. Use triggers only for centralized, global operations that should be red for the triggering statement, regardless of which user or database application issues the statement. Do not create recursive triggers. For example, creating an AFTER UPDATE statement trigger on the Emp_tab table that itself issues an UPDATE statement on Emp_tab, causes the trigger to re recursively until it has run out of memory. Use triggers on DATABASE judiciously. They are executed for every user every time the event occurs on which the trigger is created.
Creating Triggers
Triggers are created using the CREATE TRIGGER statement. This statement can be used with any interactive tool, such as SQL*Plus or Enterprise Manager. When using an interactive tool, a single slash (/) on the last line is necessary to activate the CREATE TRIGGER statement. The following statement creates a trigger for the Emp_tab table.
CREATE OR REPLACE TRIGGER Print_salary_changes BEFORE DELETE OR INSERT OR UPDATE ON Emp_tab FOR EACH ROW WHEN (new.Empno > 0) DECLARE sal_diff number; BEGIN sal_diff := :new.sal - :old.sal; dbms_output.put(Old salary: || :old.sal); dbms_output.put( New salary: || :new.sal);
15-2
Creating Triggers
The trigger is red when DML operations (INSERT, UPDATE, and DELETE statements) are performed on the table. You can choose what combination of operations should re the trigger. Because the trigger uses the BEFORE keyword, it can access the new values before they go into the table, and can change the values if there is an easily-corrected error by assigning to :NEW.column_name. You might use the AFTER keyword if you want the trigger to query or change the same table, because triggers can only do that after the initial changes are applied and the table is back in a consistent state. Because the trigger uses the FOR EACH ROW clause, it might be executed multiple times, such as when updating or deleting multiple rows. You might omit this clause if you just want to record the fact that the operation occurred, but not examine the data for each row. Once the trigger is created, entering the following SQL statement:
UPDATE Emp_tab SET sal = sal + 500.00 WHERE deptno = 10;
fires the trigger once for each row that is updated, in each case printing the new salary, old salary, and the difference. The CREATE (or CREATE OR REPLACE) statement fails if any errors exist in the PL/SQL block.
Note: The size of the trigger cannot be more than 32K.
The following sections use this example to illustrate the way that parts of a trigger are specied.
See Also: For more realistic examples of CREATE TRIGGER
Types of Triggers
A trigger is either a stored PL/SQL block or a PL/SQL, C, or Java procedure associated with a table, view, schema, or the database itself. Oracle automatically
Creating Triggers
executes a trigger when a specied event takes place, which may be in the form of a system event or a DML statement being issued against the table. Triggers can be:
s
DML triggers on tables. INSTEAD OF triggers on views. System triggers on DATABASE or SCHEMA: With DATABASE, triggers re for each event for all users; with SCHEMA, triggers re for each event for that specic user.
See Also: Oracle9i SQL Reference explains the syntax for creating
triggers.
DML statements (DELETE, INSERT, UPDATE) DDL statements (CREATE, ALTER, DROP) Database operations (SERVERERROR, LOGON, LOGOFF, STARTUP, SHUTDOWN)
the event attributes, see Chapter 16, "Working With System Events". Creating a trigger on DATABASE implies that the triggering event is outside the scope of a user (for example, database STARTUP and SHUTDOWN), and it applies to all users (for example, a trigger created on LOGON event by the DBA). Creating a trigger on SCHEMA implies that the trigger is created in the current users schema and is red only for that user. For each trigger, publication can be specied on DML and system events.
15-4
Creating Triggers
page 15-52.
Naming Triggers
Trigger names must be unique with respect to other triggers in the same schema. Trigger names do not need to be unique with respect to other schema objects, such as tables, views, and procedures. For example, a table and a trigger can have the same name (however, to avoid confusion, this is not recommended).
The SQL statement or the system event, database event, or DDL event that res the trigger body. The options include DELETE, INSERT, and UPDATE. One, two, or all three of these options can be included in the triggering statement specication. The table, view, DATABASE, or SCHEMA associated with the trigger.
Note: Exactly one table or view can be specied in the triggering
statement. If the INSTEAD OF option is used, then the triggering statement may only specify a view; conversely, if a view is specied in the triggering statement, then only the INSTEAD OF option may be used. For example, the PRINT_SALARY_CHANGES trigger res after any DELETE, INSERT, or UPDATE on the Emp_tab table. Any of the following statements trigger the PRINT_SALARY_CHANGES trigger given in the previous example:
DELETE INSERT INSERT UPDATE FROM Emp_tab; INTO Emp_tab VALUES ( ... ); INTO Emp_tab SELECT ... FROM ... ; Emp_tab SET ... ;
Creating Triggers
If IGNORE=N (default) and the table already exists, then import does not change the table and no existing triggers re. If the table does not exist, then import creates and loads it before any triggers are dened, so again no triggers re. If IGNORE=Y, then import loads rows into existing tables. Any existing triggers re, and indexes are updated to account for the imported data.
Notes:
s
You cannot specify a column list for UPDATE with INSTEAD OF triggers. If the column specied in the UPDATE OF clause is an object column, then the trigger is also red if any of the attributes of the object are modied. You cannot specify UPDATE OF clauses on collection columns.
15-6
Creating Triggers
Note: AFTER row triggers are slightly more efcient than BEFORE
row triggers. With BEFORE row triggers, affected data blocks must be read (logical read, not physical read) once for the trigger and then again for the triggering statement. Alternatively, with AFTER row triggers, the data blocks must be read only once for both the triggering statement and the trigger.
The INSTEAD OF option can only be used for triggers created over views. The BEFORE and AFTER options cannot be used for triggers created over views. The CHECK option for views is not enforced when inserts or updates to the view are done using INSTEAD OF triggers. The INSTEAD OF trigger body must enforce the check.
Creating Triggers
GROUP BY, CONNECT BY, or START WITH clauses The DISTINCT operator Joins (a subset of join views are updatable)
If a view contains pseudocolumns or expressions, then you can only update the view with an UPDATE statement that does not refer to any of the pseudocolumns or expressions.
The following example shows an INSTEAD OF trigger for inserting rows into the MANAGER_INFO view.
CREATE OR REPLACE VIEW manager_info AS SELECT e.ename, e.empno, d.dept_type, d.deptno, p.prj_level, p.projno FROM Emp_tab e, Dept_tab d, Project_tab p WHERE e.empno = d.mgr_no AND d.deptno = p.resp_dept;
15-8
Creating Triggers
CREATE OR REPLACE TRIGGER manager_info_insert INSTEAD OF INSERT ON manager_info REFERENCING NEW AS n -- new manager information FOR EACH ROW DECLARE rowcnt number; BEGIN SELECT COUNT(*) INTO rowcnt FROM Emp_tab WHERE empno = :n.empno; IF rowcnt = 0 THEN INSERT INTO Emp_tab (empno,ename) VALUES (:n.empno, :n.ename); ELSE UPDATE Emp_tab SET Emp_tab.ename = :n.ename WHERE Emp_tab.empno = :n.empno; END IF; SELECT COUNT(*) INTO rowcnt FROM Dept_tab WHERE deptno = :n.deptno; IF rowcnt = 0 THEN INSERT INTO Dept_tab (deptno, dept_type) VALUES(:n.deptno, :n.dept_type); ELSE UPDATE Dept_tab SET Dept_tab.dept_type = :n.dept_type WHERE Dept_tab.deptno = :n.deptno; END IF; SELECT COUNT(*) INTO rowcnt FROM Project_tab WHERE Project_tab.projno = :n.projno; IF rowcnt = 0 THEN INSERT INTO Project_tab (projno, prj_level) VALUES(:n.projno, :n.prj_level); ELSE UPDATE Project_tab SET Project_tab.prj_level = :n.prj_level WHERE Project_tab.projno = :n.projno; END IF; END;
The actions shown for rows being inserted into the MANAGER_INFO view rst test to see if appropriate rows already exist in the base tables from which MANAGER_INFO is derived. The actions then insert new rows or update existing rows, as appropriate. Similar triggers can specify appropriate actions for UPDATE and DELETE.
Creating Triggers
To modify an object materialized by an object view in the client-side object cache and ush it back to the persistent store, you must specify INSTEAD OF triggers, unless the object view is modiable. If the object is read only, then it is not necessary to dene triggers to pin it.
Can only be dened over nested table columns in views. Fire only when the nested table elements are modied using the THE() or TABLE() clauses. They do not re when a DML statement is performed on the view.
For example, consider a department view that contains a nested table of employees.
CREATE OR REPLACE VIEW Dept_view AS SELECT d.Deptno, d.Dept_type, d.Dept_name, CAST (MULTISET ( SELECT e.Empno, e.Empname, e.Salary FROM Emp_tab e WHERE e.Deptno = d.Deptno) AS Amp_list_ Emplist FROM Dept_tab d;
The CAST (MULTISET..) operator creates a multi-set of employees for each department. Now, if you want to modify the emplist column, which is the nested table of employees, then you can dene an INSTEAD OF trigger over the column to handle the operation. The following example shows how an insert trigger might be written:
Creating Triggers
CREATE OR REPLACE TRIGGER Dept_emplist_tr INSTEAD OF INSERT ON NESTED TABLE Emplist OF Dept_view REFERENCING NEW AS Employee PARENT AS Department FOR EACH ROW BEGIN -- The insert on the nested table is translated to an insert on the base table: INSERT INTO Emp_tab VALUES ( :Employee.Empno, :Employee.Empname,:Employee.Salary, :Department.Deptno); END;
Any INSERT into the nested table res the trigger, and the Emp_tab table is lled with the correct values. For example:
INSERT INTO TABLE (SELECT d.Emplist FROM Dept_view d WHERE Deptno = 10) VALUES (1001, John Glenn, 10000)
The :department.deptno correlation variable in this example would have a value of 10.
CREATE OR REPLACE TRIGGER Log_salary_increase AFTER UPDATE ON Emp_tab FOR EACH ROW
Creating Triggers
WHEN (new.Sal > 1000) BEGIN INSERT INTO Emp_log (Emp_id, Log_date, New_salary, Action) VALUES (:new.Empno, SYSDATE, :new.SAL, NEW SAL); END;
If there are ve employees in department 20, then the trigger res ve times when this statement is entered, because ve rows are affected. The following trigger res only once for each UPDATE of the Emp_tab table:
CREATE OR REPLACE TRIGGER Log_emp_update AFTER UPDATE ON Emp_tab BEGIN INSERT INTO Emp_log (Log_date, Action) VALUES (SYSDATE, Emp_tab COMMISSIONS CHANGED); END;
See Also: For the order of trigger ring, see Oracle9i Database
Concepts. The statement level triggers are useful for performing validation checks for the entire statement.
statement trigger. If included, then the expression in the WHEN clause is evaluated for each row that the trigger affects. If the expression evaluates to TRUE for a row, then the trigger body is red on behalf of that row. However, if the expression evaluates to FALSE or NOT TRUE for a row (unknown, as with nulls), then the trigger body is not red for that row. The evaluation of the WHEN clause does not have an effect on the execution of the
triggering SQL statement (in other words, the triggering statement is not rolled back if the expression in a WHEN clause evaluates to FALSE). For example, in the PRINT_SALARY_CHANGES trigger, the trigger body is not run if the new value of Empno is zero, NULL, or negative. In more realistic examples, you might test if one column value is less than another. The expression in a WHEN clause of a row trigger can include correlation names, which are explained later. The expression in a WHEN clause must be a SQL expression, and it cannot include a subquery. You cannot use a PL/SQL expression (including user-dened functions) in the WHEN clause.
Note: You cannot specify the WHEN clause for INSTEAD OF
triggers.
CREATE OR REPLACE PROCEDURE foo (c VARCHAR2) AS BEGIN INSERT INTO Audit_table (user_at) VALUES(c); END; CREATE OR REPLACE TRIGGER logontrig AFTER LOGON ON DATABASE -- Just call an existing procedure. The ORA_LOGIN_USER is a function -- that returns information about the event that fired the trigger. CALL foo (ora_login_user) /
Example: Calling a Java Procedure from a Trigger Although triggers are declared using PL/SQL, they can call procedures in other languages, such as Java:
CREATE OR REPLACE PROCEDURE Before_delete (Id IN NUMBER, Ename VARCHAR2) IS language Java name thjvTriggers.beforeDelete (oracle.sql.NUMBER, oracle.sql.CHAR); CREATE OR REPLACE TRIGGER Pre_del_trigger BEFORE DELETE ON Tab FOR EACH ROW CALL Before_delete (:old.Id, :old.Ename)
A trigger red by an INSERT statement has meaningful access to new column values only. Because the row is being created by the INSERT, the old values are null. A trigger red by an UPDATE statement has access to both old and new column values for both BEFORE and AFTER row triggers. A trigger red by a DELETE statement has meaningful access to :old column values only. Because the row no longer exists after the row is deleted, the :new values are NULL. However, you cannot modify :new values: ORA-4084 is raised if you try to modify :new values.
The new column values are referenced using the new qualier before the column name, while the old column values are referenced using the old qualier before the column name. For example, if the triggering statement is associated with the Emp_tab table (with the columns SAL, COMM, and so on), then you can include statements in the trigger body. For example:
IF :new.Sal > 10000 ... IF :new.Sal < :old.Sal ...
Old and new values are available in both BEFORE and AFTER row triggers. A new column value can be assigned in a BEFORE row trigger, but not in an AFTER row trigger (because the triggering statement takes effect before an AFTER row trigger is red). If a BEFORE row trigger changes the value of new.column, then an AFTER row trigger red by the same statement sees the change assigned by the BEFORE row trigger. Correlation names can also be used in the Boolean expression of a WHEN clause. A colon must precede the old and new qualiers when they are used in a triggers body, but a colon is not allowed when using the qualiers in the WHEN clause or the REFERENCING option.
CREATE OR REPLACE TRIGGER Print_salary_changes BEFORE UPDATE ON new REFERENCING new AS Newest FOR EACH ROW BEGIN :Newest.Field2 := TO_CHAR (:newest.field1); END;
Notice that the new qualier is renamed to newest using the REFERENCING option, and it is then used in the trigger body.
Detecting the DML Operation That Fired a Trigger (INSERTING, UPDATING, and DELETING Predicates)
If more than one type of DML operation can re a trigger (for example, ON INSERT OR DELETE OR UPDATE OF Emp_tab), the trigger body can use the conditional predicates INSERTING, DELETING, and UPDATING to check which type of statement fire the trigger. Within the code of the trigger body, you can execute blocks of code depending on the kind of DML operation red the trigger:
IF INSERTING THEN ... END IF; IF UPDATING THEN ... END IF;
The rst condition evaluates to TRUE only if the statement that red the trigger is an INSERT statement; the second condition evaluates to TRUE only if the statement that red the trigger is an UPDATE statement. In an UPDATE trigger, a column name can be specied with an UPDATING conditional predicate to determine if the named column is being updated. For example, assume a trigger is dened as the following:
CREATE OR REPLACE TRIGGER ... ... UPDATE OF Sal, Comm ON Emp_tab ... BEGIN ... IF UPDATING (SAL) THEN ... END IF; END;
The code in the THEN clause runs only if the triggering UPDATE statement updates the SAL column. This way, the trigger can minimize its overhead when the column of interest is not being changed.
CREATE OR REPLACE TRIGGER Example AFTER INSERT ON Emp_tab FOR EACH ROW BEGIN INSERT INTO Emp_tab@Remote -- <- compilation fails here VALUES (x); -when dblink is inaccessible EXCEPTION WHEN OTHERS THEN INSERT INTO Emp_log VALUES (x); END;
A trigger is compiled when it is created. Thus, if a remote site is unavailable when the trigger must compile, then Oracle cannot validate the statement accessing the remote database, and the compilation fails. The previous example exception statement cannot run, because the trigger does not complete compilation. Because stored procedures are stored in a compiled form, the work-around for the previous example is as follows:
CREATE OR REPLACE TRIGGER Example AFTER INSERT ON Emp_tab FOR EACH ROW BEGIN Insert_row_proc; END; CREATE OR REPLACE PROCEDURE Insert_row_proc AS BEGIN INSERT INTO Emp_tab@Remote VALUES (x); EXCEPTION WHEN OTHERS THEN INSERT INTO Emp_log VALUES (x); END;
The trigger in this example compiles successfully and calls the stored procedure, which already has a validated statement for accessing the remote database; thus, when the remote INSERT statement fails because the link is down, the exception is caught.
transaction control statements, because the procedure runs within the context of the trigger body. Statements inside a trigger can reference remote schema objects. However, pay special attention when calling remote procedures from within a local trigger. If a timestamp or signature mismatch is found during execution of the trigger, then the remote procedure is not run, and the trigger is invalidated.
A SQL statement within a trigger can insert data into a column of LONG or LONG RAW datatype. If data from a LONG or LONG RAW column can be converted to a constrained datatype (such as CHAR and VARCHAR2), then a LONG or LONG RAW column can be referenced in a SQL statement within a trigger. The maximum length for these datatypes is 32000 bytes. Variables cannot be declared using the LONG or LONG RAW datatypes. :NEW and :PARENT cannot be used with LONG or LONG RAW columns.
ring order of triggers. Each subsequent trigger sees the changes made by the previously red triggers. Each trigger can see the old and new values. The old values are the original values, and the new values are the current values, as set by the most recently red UPDATE or INSERT trigger.
To ensure that multiple triggered actions occur in a specic order, you must consolidate these actions into a single trigger (for example, by having the trigger call a series of procedures). You cannot open a database that contains multiple triggers of the same type if you are using any version of Oracle before release 7.1. You also cannot open such a database if your COMPATIBLE initialization parameter is set to a version earlier than 7.1.0. For system triggers, compatibility must be 8.1.0.
An error is returned because the table is mutating when the row is deleted:
ORA-04091: table SCOTT.Emp_tab is mutating, trigger/function may not see it
If you delete the line "FOR EACH ROW" from the trigger, it becomes a statement trigger which is not subject to this restriction, and the trigger. If you need to update a mutating table, you could bypass these restrictions by using a temporary table, a PL/SQL table, or a package variable. For example, in place of a single AFTER row trigger that updates the original table, resulting in a mutating table error, you might use two triggersan AFTER row trigger that updates a temporary table, and an AFTER statement trigger that updates the original table with the values from the temporary table. Declarative integrity constraints are checked at various times with respect to row triggers.
See Also: Oracle9i Database Concepts has information about the interaction of triggers and integrity constraints.
Because declarative referential integrity constraints are currently not supported between tables on different nodes of a distributed database, the mutating table restrictions do not apply to triggers that access remote nodes. These restrictions are also not enforced among tables in the same database that are connected by loop-back database links. A loop-back database link makes a local table appear remote by dening an Oracle Net path back to the database that contains the link. Do not use loop-back database links to circumvent the trigger restrictions. Such applications might behave unpredictably. Restrictions on Mutating Tables Relaxed Before Oracle8i, there was a "constraining error" that prevented a row trigger from modifying a table when the parent statement implicitly read that table to enforce a foreign key constraint. Starting with Oracle8i, there is no constraining error. Also, checking of the foreign key is deferred until at least the end of the parent statement. The mutating error still prevents the trigger from reading or modifying the table that the parent statement is modifying. However, starting in Oracle release 8.1, a delete against the parent table causes before/after statement triggers to be red once. That way, you can create triggers (just not row triggers) to read and modify the parent and child tables. This allows most foreign key constraint actions to be implemented through their obvious after-row trigger, providing the constraint is not self-referential. Update
cascade, update set null, update set default, delete set default, inserting a missing parent, and maintaining a count of children can all be implemented easily. For example, this is an implementation of update cascade:
create table p create table f create trigger update f set end; / (p1 number constraint ppk primary key); (f1 number constraint ffk references p); pt after update on p for each row begin f1 = :new.p1 where f1 = :old.p1;
This implementation requires care for multirow updates. For example, if a table p has three rows with the values (1), (2), (3), and table f also has three rows with the values (1), (2), (3), then the following statement updates p correctly but causes problems when the trigger updates f:
update p set p1 = p1+1;
The statement rst updates (1) to (2) in p, and the trigger updates (1) to (2) in f, leaving two rows of value (2) in f. Then the statement updates (2) to (3) in p, and the trigger updates both rows of value (2) to (3) in f. Finally, the statement updates (3) to (4) in p, and the trigger updates all three rows in f from (3) to (4). The relationship of the data in p and f is lost. To avoid this problem, you must forbid multirow updates to p that change the primary key and reuse existing primary key values. It could also be solved by tracking which foreign key values have already been updated, then modifying the trigger so that no row is updated twice. That is the only problem with this technique for foreign key updates. The trigger cannot miss rows that have been changed but not committed by another transaction, because the foreign key constraint guarantees that no matching foreign key rows are locked before the after-row trigger is called.
DROP a trigger that should be red before all DROP events, then the trigger res before the DROP. For example, if you execute the following SQL statement:
CREATE OR REPLACE TRIGGER Foo AFTER CREATE ON DATABASE BEGIN null; END;
Then, trigger foo is not red after the creation of foo. Oracle does not re a trigger that is not committed. Foreign Function Callouts All restrictions on foreign function callouts also apply.
Own the table specied in the triggering statement, or Have the ALTER privilege for the table in the triggering statement, or Have the ALTER ANY TABLE system privilege
To create a trigger in another users schema, or to reference a table in another schema from a trigger in your schema, you must have the CREATE ANY TRIGGER system privilege. With this privilege, the trigger can be created in any schema and can be associated with any users table. In addition, the user creating the trigger must also have EXECUTE privilege on the referenced procedures, functions, or packages. To create a trigger on DATABASE, you must have the ADMINISTER DATABASE TRIGGER privilege. If this privilege is later revoked, then you can drop the trigger, but not alter it.
Compiling Triggers
The object privileges to the schema objects referenced in the trigger body must be granted to the triggers owner explicitly (not through a role). The statements in the trigger body operate under the privilege domain of the triggers owner, not the privilege domain of the user issuing the triggering statement. This is similar to the privilege model for stored procedures.
Compiling Triggers
Triggers are similar to PL/SQL anonymous blocks with the addition of the :new and :old capabilities, but their compilation is different. A PL/SQL anonymous block is compiled each time it is loaded into memory. Compilation involves three stages:
1. 2. 3.
Syntax checking: PL/SQL syntax is checked, and a parse tree is generated. Semantic checking: Type checking and further processing on the parse tree. Code generation: The pcode is generated.
Triggers, in contrast, are fully compiled when the CREATE TRIGGER statement is entered, and the pcode is stored in the data dictionary. Hence, ring the trigger no longer requires the opening of a shared cursor to run the trigger action. Instead, the trigger is executed directly. If errors occur during the compilation of a trigger, then the trigger is still created. If a DML statement res this trigger, then the DML statement fails. (Runtime that trigger errors always cause the DML statement to fail.) You can use the SHOW ERRORS statement in SQL*Plus or Enterprise Manager to see any compilation errors when you create a trigger, or you can SELECT the errors from the USER_ERRORS view.
Compiling Triggers
Triggers may depend on other functions or packages. If the function or package specied in the trigger is dropped, then the trigger is marked invalid. An attempt is made to validate the trigger on occurrence of the event. If the trigger cannot be validated successfully, then it is marked VALID WITH ERRORS, and the event fails.
Note:
s
There is an exception for STARTUP events: STARTUP events succeed even if the trigger fails. There are also exceptions for SHUTDOWN events and for LOGON events if you login as SYSTEM. Because the DBMS_AQ package is used to enqueue a message, dependency between triggers and queues cannot be maintained.
Recompiling Triggers
Use the ALTER TRIGGER statement to recompile a trigger manually. For example, the following statement recompiles the PRINT_SALARY_CHANGES trigger:
ALTER TRIGGER Print_salary_changes COMPILE;
To recompile a trigger, you must own the trigger or have the ALTER ANY TRIGGER system privilege.
Modifying Triggers
Like a stored procedure, a trigger cannot be explicitly altered: It must be replaced with a new denition. (The ALTER TRIGGER statement is used only to recompile, enable, or disable a trigger.) When replacing a trigger, you must include the OR REPLACE option in the CREATE TRIGGER statement. The OR REPLACE option is provided to allow a new version of an existing trigger to replace the older version, without affecting any grants made for the original version of the trigger. Alternatively, the trigger can be dropped using the DROP TRIGGER statement, and you can rerun the CREATE TRIGGER statement. To drop a trigger, the trigger must be in your schema, or you must have the DROP ANY TRIGGER system privilege.
Debugging Triggers
You can debug a trigger using the same facilities available for stored procedures.
See Also: "Debugging Stored Procedures" on page 9-41
Enabling Triggers
By default, a trigger is automatically enabled when it is created; however, it can later be disabled. After you have completed the task that required the trigger to be disabled, re-enable the trigger, so that it res when appropriate. Enable a disabled trigger using the ALTER TRIGGER statement with the ENABLE option. To enable the disabled trigger named REORDER of the INVENTORY table, enter the following statement:
ALTER TRIGGER Reorder ENABLE;
All triggers dened for a specic table can be enabled with one statement using the ALTER TABLE statement with the ENABLE clause with the ALL TRIGGERS option. For example, to enable all triggers dened for the INVENTORY table, enter the following statement:
ALTER TABLE Inventory ENABLE ALL TRIGGERS;
Disabling Triggers
You might temporarily disable a trigger if:
s
An object it references is not available. You need to perform a large data load, and you want it to proceed quickly without ring triggers. You are reloading data.
By default, triggers are enabled when rst created. Disable a trigger using the ALTER TRIGGER statement with the DISABLE option. For example, to disable the trigger named REORDER of the INVENTORY table, enter the following statement:
ALTER TRIGGER Reorder DISABLE;
All triggers associated with a table can be disabled with one statement using the ALTER TABLE statement with the DISABLE clause and the ALL TRIGGERS option. For example, to disable all triggers dened for the INVENTORY table, enter the following statement:
ALTER TABLE Inventory DISABLE ALL TRIGGERS;
The new column, BASE_OBJECT_TYPE, species whether the trigger is based on DATABASE, SCHEMA, table, or view. The old column, TABLE_NAME, is null if the base object is not table or view. The column ACTION_TYPE species whether the trigger is a call type trigger or a PL/SQL trigger. The column TRIGGER_TYPE includes two additional values: BEFORE EVENT and AFTER EVENT, applicable only to system events. The column TRIGGERING_EVENT includes all system and DML events.
See Also: The Oracle9i Database Reference provides a complete
description of these data dictionary views. For example, assume the following statement was used to create the REORDER trigger:
Caution: You may need to set up data structures for certain
examples to work:
CREATE OR REPLACE TRIGGER Reorder AFTER UPDATE OF Parts_on_hand ON Inventory FOR EACH ROW WHEN(new.Parts_on_hand < new.Reorder_point) DECLARE x NUMBER; BEGIN SELECT COUNT(*) INTO x FROM Pending_orders WHERE Part_no = :new.Part_no; IF x = 0 THEN INSERT INTO Pending_orders VALUES (:new.Part_no, :new.Reorder_quantity, sysdate); END IF; END;
The following two queries return information about the REORDER trigger:
SELECT Trigger_type, Triggering_event, Table_name FROM USER_TRIGGERS WHERE Trigger_name = REORDER;
TYPE TRIGGERING_STATEMENT TABLE_NAME ---------------- -------------------------- -----------AFTER EACH ROW UPDATE INVENTORY SELECT Trigger_body FROM USER_TRIGGERS WHERE Trigger_name = REORDER; TRIGGER_BODY -------------------------------------------DECLARE x NUMBER; BEGIN SELECT COUNT(*) INTO x FROM Pending_orders WHERE Part_no = :new.Part_no; IF x = 0 THEN INSERT INTO Pending_orders VALUES (:new.Part_no, :new.Reorder_quantity, sysdate); END IF; END;
Provide sophisticated auditing Prevent invalid transactions Enforce referential integrity (either those actions not supported by declarative integrity constraints or across nodes in a distributed database) Enforce complex business rules Enforce complex security authorizations Provide transparent event logging Automatically generate derived column values Enable building complex views that are updatable Track system events
This section provides an example of each of these trigger applications. These examples are not meant to be used exactly as written: They are provided to assist you in designing your own triggers.
Standard auditing options permit auditing of DML and DDL statements regarding all types of schema objects and structures. Comparatively, triggers permit auditing of DML statements entered against tables, and DDL auditing at SCHEMA or DATABASE level. All database audit information is recorded centrally and automatically using the auditing features of Oracle. Auditing features enabled using the standard Oracle features are easier to declare and maintain, and less prone to errors, when compared to auditing functions dened by triggers. Any changes to existing auditing options can also be audited to guard against malicious database activity.
Session and Execution Using the database auditing features, records can be time Auditing generated once every time an audited statement is entered (BY ACCESS) or once for every session that enters an audited statement (BY SESSION). Triggers cannot audit by session; an audit record is generated each time a trigger-audited table is referenced.
Audit Feature
Database auditing can be set to audit when unsuccessful data access occurs. However, unless autonomous transactions are used, any audit information generated by a trigger is rolled back if the triggering statement is rolled back. For more information on autonomous transactions, see Oracle9i Database Concepts. Connections and disconnections, as well as session activity (physical I/Os, logical I/Os, deadlocks, and so on), can be recorded using standard database auditing.
When using triggers to provide sophisticated auditing, AFTER triggers are normally used. By using AFTER triggers, auditing information is recorded after the triggering statement is subjected to any applicable integrity constraints, preventing cases where the audit processing is carried out unnecessarily for statements that generate exceptions to integrity constraints. Choosing between AFTER row and AFTER statement triggers depends on the information being audited. For example, row triggers provide value-based auditing for each table row. Triggers can also require the user to supply a "reason code" for issuing the audited SQL statement, which can be useful in both row and statement-level auditing situations. The following example demonstrates a trigger that audits modications to the Emp_tab table for each row. It requires that a "reason code" be stored in a global package variable before the update. This shows how triggers can be used to provide value-based auditing and how to use public package variables.
Note: You may need to set up the following data structures for the
examples to work:
CREATE OR REPLACE PACKAGE Auditpackage AS Reason VARCHAR2(10); PROCEDURE Set_reason(Reason VARCHAR2); END; CREATE TABLE Emp99 ( Empno NOT NULL NUMBER(4) Ename VARCHAR2(10) Job VARCHAR2(9) Mgr NUMBER(4) Hiredate DATE Sal NUMBER(7,2) Comm NUMBER(7,2) Deptno NUMBER(2) Bonus NUMBER Ssn NUMBER Job_classification NUMBER); CREATE TABLE Audit_employee ( Oldssn NUMBER Oldname VARCHAR2(10) Oldjob VARCHAR2(2) Oldsal NUMBER Newssn NUMBER Newname VARCHAR2(10) Newjob VARCHAR2(2) Newsal NUMBER Reason VARCHAR2(10) User1 VARCHAR2(10) Systemdate DATE);
CREATE OR REPLACE TRIGGER Audit_employee AFTER INSERT OR DELETE OR UPDATE ON Emp99 FOR EACH ROW BEGIN /* AUDITPACKAGE is a package with a public package variable REASON. REASON could be set by the application by a command such as EXECUTE AUDITPACKAGE.SET_REASON(reason_string). Note that a package variable has state for the duration of a session and that each session has a separate copy of all package variables. */ IF Auditpackage.Reason IS NULL THEN Raise_application_error(-20201, Must specify reason || with AUDITPACKAGE.SET_REASON(Reason_string)); END IF; /* If the above conditional evaluates to TRUE, the user-specified error number and message is raised, the trigger stops execution, and the effects of the triggering statement are rolled back. Otherwise, a new row is inserted into the predefined auditing table named AUDIT_EMPLOYEE containing the existing and new values of the Emp_tab table and the reason code defined by the REASON variable of AUDITPACKAGE. Note that the "old" values are NULL if triggering statement is an INSERT and the "new" values are NULL if the triggering statement is a DELETE. */ INSERT INTO Audit_employee VALUES (:old.Ssn, :old.Ename, :old.Job_classification, :old.Sal, :new.Ssn, :new.Ename, :new.Job_classification, :new.Sal, auditpackage.Reason, User, Sysdate ); END;
Optionally, you can also set the reason code back to NULL if you wanted to force the reason code to be set for every update. The following simple AFTER statement trigger sets the reason code back to NULL after the triggering statement is run:
CREATE OR REPLACE TRIGGER Audit_employee_reset AFTER INSERT OR DELETE OR UPDATE ON Emp_tab BEGIN auditpackage.set_reason(NULL); END;
Notice that the previous two triggers are both red by the same type of SQL statement. However, the AFTER row trigger is red once for each row of the table affected by the triggering statement, while the AFTER statement trigger is red only once after the triggering statement execution is completed. This next trigger also uses triggers to do auditing. It tracks changes made to the Emp_tab table and stores this information in AUDIT_TABLE and AUDIT_TABLE_VALUES.
Note: You may need to set up the following data structures for the
example to work:
CREATE TABLE Audit_table ( Seq NUMBER, User_at VARCHAR2(10), Time_now DATE, Term VARCHAR2(10), Job VARCHAR2(10), Proc VARCHAR2(10), enum NUMBER); CREATE SEQUENCE Audit_seq; CREATE TABLE Audit_table_values ( Seq NUMBER, Dept NUMBER, Dept1 NUMBER, Dept2 NUMBER);
CREATE OR REPLACE TRIGGER Audit_emp AFTER INSERT OR UPDATE OR DELETE ON Emp_tab FOR EACH ROW DECLARE Time_now DATE; Terminal CHAR(10); BEGIN -- get current time, and the terminal of the user: Time_now := SYSDATE; Terminal := USERENV(TERMINAL); -- record new employee primary key IF INSERTING THEN INSERT INTO Audit_table VALUES (Audit_seq.NEXTVAL, User, Time_now, Terminal, Emp_tab, INSERT, :new.Empno); -- record primary key of the deleted row: ELSIF DELETING THEN
INSERT INTO Audit_table VALUES (Audit_seq.NEXTVAL, User, Time_now, Terminal, Emp_tab, DELETE, :old.Empno); -- for updates, record the primary key -- of the row being updated: ELSE INSERT INTO Audit_table VALUES (audit_seq.NEXTVAL, User, Time_now, Terminal, Emp_tab, UPDATE, :old.Empno); -- and for SAL and DEPTNO, record old and new values: IF UPDATING (SAL) THEN INSERT INTO Audit_table_values VALUES (Audit_seq.CURRVAL, SAL, :old.Sal, :new.Sal); ELSIF UPDATING (DEPTNO) THEN INSERT INTO Audit_table_values VALUES (Audit_seq.CURRVAL, DEPTNO, :old.Deptno, :new.DEPTNO); END IF; END IF; END;
Constraints" Triggers constrain what a transaction can do. A trigger does not apply to data loaded before the denition of the trigger; therefore, it is not known if all data in a table conforms to the rules established by an associated trigger. Although triggers can be written to enforce many of the same rules supported by Oracles declarative integrity constraint features, triggers should only be used to enforce complex business rules that cannot be dened using standard integrity constraints. The declarative integrity constraint features provided with Oracle offer the following advantages when compared to constraints dened by triggers:
Centralized integrity checks. All points of data access must adhere to the global set of rules dened by the integrity constraints corresponding to each schema object. Declarative method. Constraints dened using the standard integrity constraint features are much easier to write and are less prone to errors, when compared with comparable constraints dened by triggers. While most aspects of data integrity can be dened and enforced using declarative integrity constraints, triggers can be used to enforce complex business constraints not denable using declarative integrity constraints. For example, triggers can be used to enforce:
s
UPDATE and DELETE SET NULL, and UPDATE and DELETE SET DEFAULT referential actions. Referential integrity when the parent and child tables are on different nodes of a distributed database. Complex check constraints not denable using the expressions allowed in a CHECK constraint.
A trigger must be dened for the child table that guarantees values inserted or updated in the foreign key correspond to values in the parent key. One or more triggers must be dened for the parent table. These triggers guarantee the desired referential action (RESTRICT, CASCADE, or SET NULL) for values in the foreign key when values are updated or deleted in the parent key.
No action is required for inserts into the parent table (no dependent foreign keys exist). The following sections provide examples of the triggers necessary to enforce referential integrity. The Emp_tab and Dept_tab table relationship is used in these examples. Several of the triggers include statements that lock rows (SELECT... FOR UPDATE). This operation is necessary to maintain concurrency as the rows are being processed. Foreign Key Trigger for Child Table The following trigger guarantees that before an INSERT or UPDATE statement affects a foreign key value, the corresponding value exists in the parent key. The mutating table exception included in the following example allows this trigger to be used with the UPDATE_SET_DEFAULT and UPDATE_CASCADE triggers. This exception can be removed if this trigger is used alone.
CREATE OR REPLACE TRIGGER Emp_dept_check BEFORE INSERT OR UPDATE OF Deptno ON Emp_tab FOR EACH ROW WHEN (new.Deptno IS NOT NULL)
-- Before a row is inserted, or DEPTNO is updated in the Emp_tab -- table, fire this trigger to verify that the new foreign -- key value (DEPTNO) is present in the Dept_tab table. DECLARE Dummy INTEGER; -- used for cursor fetch below Invalid_department EXCEPTION; Valid_department EXCEPTION; Mutating_table EXCEPTION; PRAGMA EXCEPTION_INIT (Mutating_table, -4091); ----Cursor used to verify parent key value exists. If present, lock parent keys row so it cant be deleted by another transaction until this transaction is committed or rolled back. CURSOR Dummy_cursor (Dn NUMBER) IS SELECT Deptno FROM Dept_tab WHERE Deptno = Dn FOR UPDATE OF Deptno; BEGIN OPEN Dummy_cursor (:new.Deptno); FETCH Dummy_cursor INTO Dummy; -- Verify parent key. If not found, raise user-specified
-- error number and message. If found, close cursor -- before allowing triggering statement to complete: IF Dummy_cursor%NOTFOUND THEN RAISE Invalid_department; ELSE RAISE valid_department; END IF; CLOSE Dummy_cursor; EXCEPTION WHEN Invalid_department THEN CLOSE Dummy_cursor; Raise_application_error(-20000, Invalid Department || Number || TO_CHAR(:new.deptno)); WHEN Valid_department THEN CLOSE Dummy_cursor; WHEN Mutating_table THEN NULL; END;
UPDATE and DELETE RESTRICT Trigger for Parent Table The following trigger is dened on the DEPT_TAB table to enforce the UPDATE and DELETE RESTRICT referential action on the primary key of the DEPT_TAB table:
CREATE OR REPLACE TRIGGER Dept_restrict BEFORE DELETE OR UPDATE OF Deptno ON Dept_tab FOR EACH ROW
-- Before a row is deleted from Dept_tab or the primary key -- (DEPTNO) of Dept_tab is updated, check for dependent -- foreign key values in Emp_tab; rollback if any are found. DECLARE Dummy INTEGER; -- used for cursor fetch below Employees_present EXCEPTION; employees_not_present EXCEPTION; -- Cursor used to check for dependent foreign key values. CURSOR Dummy_cursor (Dn NUMBER) IS SELECT Deptno FROM Emp_tab WHERE Deptno = Dn;
BEGIN OPEN Dummy_cursor (:old.Deptno); FETCH Dummy_cursor INTO Dummy; -- If dependent foreign key is found, raise user-specified -- error number and message. If not found, close cursor -- before allowing triggering statement to complete.
IF Dummy_cursor%FOUND THEN RAISE Employees_present; -- dependent rows exist ELSE RAISE Employees_not_present; -- no dependent rows END IF; CLOSE Dummy_cursor; EXCEPTION WHEN Employees_present THEN CLOSE Dummy_cursor; Raise_application_error(-20001, Employees Present in || Department || TO_CHAR(:old.DEPTNO)); WHEN Employees_not_present THEN CLOSE Dummy_cursor; END;
(tables with both the primary/unique key and the foreign key). Also, this trigger does not allow triggers to cycle (such as, A res B res A). UPDATE and DELETE SET NULL Triggers for Parent Table: Example The following trigger is dened on the DEPT_TAB table to enforce the UPDATE and DELETE SET NULL referential action on the primary key of the DEPT_TAB table:
CREATE OR REPLACE TRIGGER Dept_set_null AFTER DELETE OR UPDATE OF Deptno ON Dept_tab FOR EACH ROW
-- Before a row is deleted from Dept_tab or the primary key -- (DEPTNO) of Dept_tab is updated, set all corresponding -- dependent foreign key values in Emp_tab to NULL: BEGIN IF UPDATING AND :OLD.Deptno != :NEW.Deptno OR DELETING THEN UPDATE Emp_tab SET Emp_tab.Deptno = NULL WHERE Emp_tab.Deptno = :old.Deptno; END IF; END;
DELETE Cascade Trigger for Parent Table: Example The following trigger on the DEPT_TAB table enforces the DELETE CASCADE referential action on the primary key of the DEPT_TAB table:
CREATE OR REPLACE TRIGGER Dept_del_cascade
-- Before a row is deleted from Dept_tab, delete all -- rows from the Emp_tab table whose DEPTNO is the same as -- the DEPTNO being deleted from the Dept_tab table: BEGIN DELETE FROM Emp_tab WHERE Emp_tab.Deptno = :old.Deptno; END;
the code for UPDATE SET NULL or UPDATE SET DEFAULT to account for both updates and deletes. UPDATE Cascade Trigger for Parent Table: Example The following trigger ensures that if a department number is updated in the Dept_tab table, then this change is propagated to dependent foreign keys in the Emp_tab table:
-- Generate a sequence number to be used as a flag for -- determining if an update has occurred on a column: CREATE SEQUENCE Update_sequence INCREMENT BY 1 MAXVALUE 5000 CYCLE;
CREATE OR REPLACE PACKAGE Integritypackage AS Updateseq NUMBER; END Integritypackage; CREATE OR REPLACE PACKAGE BODY Integritypackage AS END Integritypackage; -- create flag col: ALTER TABLE Emp_tab ADD Update_id NUMBER; . CREATE OR REPLACE TRIGGER Dept_cascade1 BEFORE UPDATE OF Deptno ON Dept_tab DECLARE Dummy NUMBER;
-- Before updating the Dept_tab table (this is a statement -- trigger), generate a new sequence number and assign -- it to the public variable UPDATESEQ of a user-defined -- package named INTEGRITYPACKAGE: BEGIN SELECT Update_sequence.NEXTVAL
INTO Dummy FROM dual; Integritypackage.Updateseq := Dummy; END; CREATE OR REPLACE TRIGGER Dept_cascade2 AFTER DELETE OR UPDATE OF Deptno ON Dept_tab FOR EACH ROW
-- For each department number in Dept_tab that is updated, -- cascade the update to dependent foreign keys in the -- Emp_tab table. Only cascade the update if the child row -- has not already been updated by this trigger: BEGIN IF UPDATING THEN UPDATE Emp_tab SET Deptno = :new.Deptno, Update_id = Integritypackage.Updateseq --from 1st WHERE Emp_tab.Deptno = :old.Deptno AND Update_id IS NULL; /* only NULL if not updated by the 3rd trigger fired by this same triggering statement */ END IF; IF DELETING THEN -- Before a row is deleted from Dept_tab, delete all -- rows from the Emp_tab table whose DEPTNO is the same as -- the DEPTNO being deleted from the Dept_tab table: DELETE FROM Emp_tab WHERE Emp_tab.Deptno = :old.Deptno; END IF; END; CREATE OR REPLACE TRIGGER Dept_cascade3 AFTER UPDATE OF Deptno ON Dept_tab BEGIN UPDATE Emp_tab SET Update_id = NULL WHERE Update_id = Integritypackage.Updateseq; END;
Emp_dept_check trigger, if enabled, is also red. The resulting mutating table error is trapped by the Emp_dept_check trigger. You should carefully test any triggers that require error trapping to succeed to ensure that they always work properly in your environment.
example to work:
CREATE TABLE Salgrade ( Grade Losal Hisal Job_classification NUMBER, NUMBER, NUMBER, NUMBER)
CREATE OR REPLACE TRIGGER Salary_check BEFORE INSERT OR UPDATE OF Sal, Job ON Emp99 FOR EACH ROW DECLARE Minsal NUMBER; Maxsal NUMBER; Salary_out_of_range EXCEPTION; BEGIN
/* Retrieve the minimum and maximum salary for the employees new job classification from the SALGRADE table into MINSAL and MAXSAL: */
SELECT Minsal, Maxsal INTO Minsal, Maxsal FROM Salgrade WHERE Job_classification = :new.Job;
/* If the employees new salary is less than or greater than the job classifications limits, the exception is raised. The exception message is returned and the pending INSERT or UPDATE statement that fired the trigger is rolled back:*/
IF (:new.Sal < Minsal OR :new.Sal > Maxsal) THEN RAISE Salary_out_of_range; END IF; EXCEPTION WHEN Salary_out_of_range THEN Raise_application_error (-20300, Salary ||TO_CHAR(:new.Sal)|| out of range for
||job classification ||:new.Job || for employee ||:new.Ename); WHEN NO_DATA_FOUND THEN Raise_application_error(-20322, Invalid Job Classification ||:new.Job_classification); END;
The security check is done before the triggering statement is allowed to run, so that no wasted work is done by an unauthorized statement. The security check is performed only once for the triggering statement, not for each row affected by the triggering statement.
example to work:
CREATE TABLE Company_holidays (Day DATE);
CREATE OR REPLACE TRIGGER Emp_permit_changes BEFORE INSERT OR DELETE OR UPDATE ON Emp99 DECLARE Dummy INTEGER; Not_on_weekends EXCEPTION; Not_on_holidays EXCEPTION; Non_working_hours EXCEPTION; BEGIN /* check for weekends: */ IF (TO_CHAR(Sysdate, DY) = SAT OR TO_CHAR(Sysdate, DY) = SUN) THEN RAISE Not_on_weekends; END IF;
/* check for company holidays:*/ SELECT COUNT(*) INTO Dummy FROM Company_holidays WHERE TRUNC(Day) = TRUNC(Sysdate); /* TRUNC gets rid of time parts of dates: */ IF dummy > 0 THEN RAISE Not_on_holidays; END IF; /* Check for work hours (8am to 6pm): */ IF (TO_CHAR(Sysdate, HH24) < 8 OR TO_CHAR(Sysdate, HH24) > 18) THEN RAISE Non_working_hours; END IF; EXCEPTION WHEN Not_on_weekends THEN Raise_application_error(-20324,May not change ||employee table during the weekend); WHEN Not_on_holidays THEN Raise_application_error(-20325,May not change ||employee table during a holiday); WHEN Non_working_hours THEN Raise_application_error(-20326,May not change ||Emp_tab table during non-working hours); END;
The dependent values must be derived before the INSERT or UPDATE occurs, so that the triggering statement can use the derived values. The trigger must re for each row affected by the triggering INSERT or UPDATE statement.
The following example illustrates how a trigger can be used to derive new column values for a table whenever a row is inserted or updated.
Note: You may need to set up the following data structures for the
example to work:
ALTER TABLE Emp99 ADD( Uppername VARCHAR2(20), Soundexname VARCHAR2(20));
/* Before updating the ENAME field, derive the values for the UPPERNAME and SOUNDEXNAME fields. Users should be restricted from updating these fields directly: */ FOR EACH ROW BEGIN :new.Uppername := UPPER(:new.Ename); :new.Soundexname := SOUNDEX(:new.Ename); END;
CREATE OR REPLACE TYPE Book_t AS OBJECT ( Booknum NUMBER, Title VARCHAR2(20), Author VARCHAR2(20), Available CHAR(1) ); CREATE OR REPLACE TYPE Book_list_t AS TABLE OF Book_t;
Available Y N
Now you can dene a complex view over these tables to create a logical view of the library with sections and a collection of books in each section.
CREATE OR REPLACE VIEW Library_view AS SELECT i.Section, CAST (MULTISET ( SELECT b.Booknum, b.Title, b.Author, b.Available FROM Book_table b WHERE b.Section = i.Section) AS Book_list_t) BOOKLIST FROM Library_table i;
Make this view updatable by dening an INSTEAD OF trigger over the view.
CREATE OR REPLACE TRIGGER Library_trigger INSTEAD OF INSERT ON Library_view FOR EACH ROW Bookvar BOOK_T; i INTEGER;
BEGIN INSERT INTO Library_table VALUES (:NEW.Section); FOR i IN 1..:NEW.Booklist.COUNT LOOP Bookvar := Booklist(i); INSERT INTO book_table VALUES ( Bookvar.booknum, :NEW.Section, Bookvar.Title, Bookvar.Author, bookvar.Available); END LOOP; END; /
Now, the library_view is an updatable view, and any INSERTs on the view are handled by the trigger that gets red automatically. For example:
INSERT INTO Library_view VALUES (History, book_list_t(book_t(121330, Alexander, Mirth, Y);
Similarly, you can also dene triggers on the nested table booklist to handle modication of the nested table element.
REM ================================================================= REM Creation of the package which implements the context: REM =================================================================
CREATE OR REPLACE PACKAGE Exprep_ctx AS PROCEDURE Set_ctx; END; SHOW ERRORS
CREATE OR REPLACE PACKAGE BODY Exprep_ctx IS PROCEDURE Set_ctx IS Empnum NUMBER; Countrec NUMBER; Cc NUMBER; Role VARCHAR2(20); BEGIN
-- SET emp_number: SELECT Employee_id INTO Empnum FROM Employee WHERE Last_name = SYS_CONTEXT(userenv, session_user);
DBMS_SESSION.SET_CONTEXT(expenses_reporting,emp_number, Empnum);
-- SET ROLE: SELECT COUNT (*) INTO Countrec FROM Cost_center WHERE Manager_id=Empnum; IF (countrec > 0) THEN DBMS_SESSION.SET_CONTEXT(expenses_reporting,exp_role,MANAGER); ELSE DBMS_SESSION.SET_CONTEXT(expenses_reporting,exp_role,EMPLOYEE); END IF; -- SET cc_number: SELECT Cost_center_id INTO Cc FROM Employee WHERE Last_name = SYS_CONTEXT(userenv,session_user); DBMS_SESSION.SET_CONTEXT(expenses_reporting,cc_number,Cc); END; END;
CALL Syntax
CREATE OR REPLACE TRIGGER Secdemo.Setexpseetx AFTER LOGON ON DATABASE CALL Secdemo.Exprep_etx.Set_otx
Infrastructure for publish/subscribe, by making the database an active publisher of events. Integration of data cartridges in the server. The system events publication can be used to notify cartridges of state changes in the server. Integration of ne-grained access control in the server.
By creating a trigger, you can specify a procedure that runs when an event occurs. DML events are supported on tables, and system events are supported on DATABASE and SCHEMA. You can turn notication on and off by enabling and disabling the trigger using the ALTER TRIGGER statement. This feature is integrated with the Advanced Queueing engine. Publish/subscribe applications use the DBMS_AQ.ENQUEUE() procedure, and other applications such as cartridges use callouts.
See Also: Oracle9i SQL Reference
For details on how to subscribe to published events, see Oracle9i Application Developers Guide - Advanced Queuing
cannot dene your own event conditions. When an event occurs, all triggers that are enabled on that event are red, with some exceptions:
If the trigger is actually the target of the triggering event, it is not red. For example, a trigger for all DROP events is not red when it is dropped itself. If a trigger is not red if it has been modied but not committed within the same transaction as the ring event. For example, recursive DDL within a system trigger might modify a trigger, which prevents the modied trigger from being red by events within the same transaction.
More than one trigger can be created on an object. When an event res more than one trigger, the order is not dened and you should not rely on the triggers being red in a particular order.
Publication Context
When an event is published, certain runtime context and attributes, as specied in the parameter list, are passed to the callout procedure. A set of functions called event attribute functions are provided.
See Also: For event-specic attributes, see "Event Attribute
Functions" on page 16-2. For each system event supported, event-specic attributes are identied and predened for the event. You can choose the parameter list to be any of these attributes, along with other simple expressions. For callouts, these are passed as IN arguments.
Error Handling
Return status from publication callout functions for all events are ignored. For example, with SHUTDOWN events, the server cannot do anything with the return status.
See Also: For details on return status, see "List of Database Events" on page 16-8.
Execution Model
Traditionally, triggers execute as the dener of the trigger. The trigger action of an event is executed as the dener of the action (as the dener of the package or function in callouts, or as owner of the trigger in queues). Because the owner of the trigger must have EXECUTE privileges on the underlying queues, packages, or procedure, this behavior is consistent.
16
Working With System Events
System events, like LOGON and SHUTDOWN, provide a mechanism for tracking system changes. Oracle lets you combine this tracking with database event notication, which provides a simple and elegant method of delivering asynchrononous messaging to an application. This chapter includes descriptions of the various events on which triggers can be created. It also provides the list of event attribute functions. Topics include the following:
s
To use the information in this chapter, you need to understand Chapter 15, "Using Triggers". You access the event information inside a trigger body. You can set up a exible system for handling events using the Event panels in Oracle Enterprise Manager. This technique lets you detect more conditions than the system events in this chapter, and lets you set up actions such as invoking shell scripts.
16-1
To make these attributes available, you must rst run the CATPROC.SQL script. The trigger dictionary object maintains metadata about events that will be published and their corresponding attributes. In earlier releases, these functions were accessed through the SYS package. We recommend you use these public synonyms whose names begin with ora_.
Returns the IP if (ora_sysevent = LOGON) then addr := address of the client in a ora_client_ip_address; LOGON event, end if; when the underlying protocol is TCP/IP Database name. DECLARE db_name VARCHAR2(50); BEGIN db_name := ora_database_name; END; IF (ora_dict_obj_type = USER) THEN INSERT INTO event_table (ora_des_encrypted_password); END IF;
ora_database_name
VARCHAR2(50)
ora_des_encrypted_password
VARCHAR2
The DES encrypted password of the user being created or altered. Name of the dictionary object on which the DDL operation occurred.
ora_dict_obj_name
VARCHAR(30)
16-2
BINARY_INTEGER Return the list of object names of objects being modied in the event. VARCHAR(30) Owner of the dictionary object on which the DDL operation occurred.
ora_dict_obj_owner
ora_dict_obj_owner_list(owne BINARY_INTEGER Returns the list r_list OUT ora_name_list_t) of object owners of objects being modied in the event.
if (ora_sysevent = ASSOCIATE STATISTICS) then number_of_modified_objects := ora_dict_obj_owner_list(owner_li st); end if; INSERT INTO event_table (This object is a || ora_dict_obj_type);
ora_dict_obj_type
VARCHAR(20)
BINARY_INTEGER Returns the grantees of a grant event in the OUT parameter; returns the number of grantees in the return value. NUMBER
ora_instance_num
Instance number. IF (ora_instance_num = 1) THEN INSERT INTO event_table (1); END IF; Returns true if if (ora_sysevent = ALTER and the specied col- ora_dict_obj_type = TABLE) umn is altered. then alter_column := ora_is_alter_column(FOO); end if;
BOOLEAN
16-3
ora_is_creating_nested_table BOOLEAN
Return TRUE if if (ora_sysevent = CREATE and the current event ora_dict_obj_type = TABLE and is creating a ora_is_creating_nested_table) then insert into event_tab nested table values (A nested table is created); end if; Returns true if if (ora_sysevent = ALTER and the specied col- ora_dict_obj_type = TABLE) umn is dropped. then drop_column := ora_is_drop_column(FOO); end if; Returns TRUE if given error is on error stack, FALSE otherwise. IF (ora_is_servererror(error_number )) THEN INSERT INTO event_table (Server error!!); END IF;
BOOLEAN
ora_is_servererror
BOOLEAN
ora_login_user ora_partition_pos
VARCHAR2(30)
Login user name. SELECT ora_login_user FROM dual; -- Retrieve ora_sql_txt into -- sql_text variable first. n := ora_partition_pos; new_stmt := substr(sql_text, 1, n-1) || || my_partition_clause || || substr(sql_text, n));
BINARY_INTEGER In an INSTEAD OF trigger for CREATE TABLE, the position within the SQL text where you could insert a PARTITION clause.
16-4
BINARY_INTEGER Returns the list of privileges being granted by the grantee or the list of privileges revoked from the revokee in the OUT parameter; returns the number of privileges in the return value. BINARY_INTEGER Returns the revokees of a revoke event in the OUT parameter; returns the number of revokees in the return value.. NUMBER
ora_server_error
Given a position INSERT INTO event_table (top (1 for top of stack error || stack), it returns ora_server_error(1)); the error number at that position on error stack n := ora_server_error_depth; -- This value is used with -- other functions such as -- ora_server_error
ora_server_error_depth
BINARY_INTEGER Returns the total number of error messages on the error stack.
Given a position INSERT INTO event_table (top (1 for top of stack error message || stack), it returns ora_server_error_msg(1)); the error message at that position on error stack
16-5
ora_server_error_num_params BINARY_INTEGER Given a position (1 for top of (position in binary_integer) stack), it returns the number of strings that have been substituted into the error message using a format like "%s". ora_server_error_param VARCHAR2 (position in binary_integer, param in binary_integer) Given a position (1 for top of stack) and a parameter number, returns the matching "%s", "%d", and so on substitution value in the error message.
-- E.g. the 2rd %s in a message -- like "Expected %s, found %s" param := ora_server_error_param(1,2);
BINARY_INTEGER Returns the SQL text of the triggering statement in the OUT parameter. If the statement is long, it is broken up into multiple PL/SQL table elements. The function return value species how many elements are in the PL/SQL table.
sql_text ora_name_list_t; stmt VARCHAR2(2000); ... n := ora_sql_txt(sql_text); FOR i IN 1..n LOOP stmt := stmt || sql_text(i); END LOOP; INSERT INTO event_table (text of triggering statement: || stmt);
16-6
System event INSERT INTO event_table ring the trigger: (ora_sysevent); Event name is same as that in the syntax. Returns true if if (ora_sysevent = GRANT and the privileges are ora_with_grant_option = TRUE) then insert into event_table granted with (with grant option); grant option. end if; Returns true if the error is related to an out-of-space condition, and lls in the OUT parameters with information about the object that caused the error. if (space_error_info(eno, typ, owner, ts, obj, subobj) = TRUE) then dbms_output.put_line(The object || obj || owned by || owner || has run out of space.); end if;
ora_with_grant_option
BOOLEAN
space_error_info( error_number OUT NUMBER, error_type OUT VARCHAR2, object_owner OUT VARCHAR2, table_space_name OUT VARCHAR2, object_name OUT VARCHAR2, sub_object_name OUT VARCHAR2)
BOOLEAN
16-7
16-8
Client Events
Client events are the events related to user logon/logoff, DML, and DDL operations. For example:
CREATE OR REPLACE TRIGGER On_Logon AFTER LOGON ON The_user.Schema BEGIN Do_Something; END;
The LOGON and LOGOFF events allow simple conditions on UID( ) and USER( ). All other events allow simple conditions on the type and name of the object, as well as functions like UID( ) and USER( ). The LOGON event starts a separate transaction and commits it after ring the triggers. All other events re the triggers in the existing user transaction. The LOGON and LOGOFF events can operate on any objects. For all other events, the corresponding trigger cannot perform any DDL operations, such as DROP and ALTER, on the object that caused the event to be generated. The DDL allowed inside these triggers is altering, creating, or dropping a table, creating a trigger, and compile operations. If an event trigger becomes the target of a DDL operation (such as CREATE TRIGGER), it cannot be red later during the same transaction Table 163 contains a list of client events.
16-9
When most SQL DDL statements are issued. Not red for ALTER DATABASE, CREATE CONTROLFILE, CREATE DATABASE, and DDL issued through the PL/SQL procedure interface, such as creating an advanced queue. When a disassociate statistics statement is issued
16-11
BEFORE LOGOFF
AFTER LOGON
When a revoke statement is issued ora_sysevent ora_login_user ora_instance_num ora_database_name ora_dict_obj_name ora_dict_obj_type ora_dict_obj_owner ora_revokee ora_privileges After a SQL statement is suspended because of an out-of-space condition. The trigger should correct the condition so the statement can be resumed. ora_sysevent ora_login_user ora_instance_num ora_database_name ora_server_error ora_is_servererror space_error_info ora_sysevent ora_login_user ora_instance_num ora_database_name ora_dict_obj_name ora_dict_obj_type ora_dict_obj_owner
AFTER SUSPEND
16-13
17
Using the Publish-Subscribe Model for Applications
Because the database is the most signicant resource of information within the enterprise, Oracle created a publish-subscribe solution for enterprise information delivery and messaging to complement this role. Topics in this chapter include:
s
Introduction to Publish-Subscribe
Introduction to Publish-Subscribe
Networking technologies and products now enable a high degree of connectivity across a large number of computers, applications, and users. In these environments, it is important to provide asynchronous communications for the class of distributed systems that operate in a loosely-coupled and autonomous fashion, and which require operational immunity from network failures. This requirement has been lled by various middleware products that are characterized as messaging, message oriented middleware (MOM), message queuing, or publish-subscribe. Applications that communicate through a publish and subscribe paradigm require the sending applications (publishers) to publish messages without explicitly specifying recipients or having knowledge of intended recipients. Similarly, receiving applications (subscribers) must receive only those messages that the subscriber has registered an interest in. This decoupling between senders and recipients is usually accomplished by an intervening entity between the publisher and the subscriber, which serves as a level of indirection. This intervening entity is a queue that represents a subject or channel. Figure 171 illustrates publish and subscribe functionality.
Figure 171 Oracle Publish-Subscribe Functionality
Rules
Subscriptions Topic Publisher Agent receive notification/ message Subject, Channel subscribe register
Subscriber Agent
A subscriber subscribes to a queue by expressing interest in messages enqueued to that queue and by using a subject- or content-based rule as a lter. This results in a set of rule-based subscriptions associated with a given queue.
17-2
Publish-Subscribe Architecture
At runtime, publishers post messages to various queues. The queue (in other words, the delivery mechanisms of the underlying infrastructure) then delivers messages that match the various subscriptions to the appropriate subscribers.
Publish-Subscribe Architecture
Oracle includes the following features to support database-enabled publish-subscribe messaging:
s
Database Events
Database events support declarative denitions for publishing database events, detection, and run-time publication of such events. This feature enables active publication of information to end-users in an event-driven manner, to complement the traditional pull-oriented approaches to accessing information.
See Also: Chapter 16, "Working With System Events"
Advanced Queuing
Oracle Advanced Queuing supports a queue-based publish-subscribe paradigm. Database queues serve as a durable store for messages, along with capabilities to allow publish and subscribe based on queues. A rules-engine and subscription service dynamically route messages to recipients based on expressed interest. This allows decoupling of addressing between senders and receivers to complement the existing explicit sender-receiver message addressing.
See Also: Oracle9i Application Developers Guide - Advanced
Queuing
Client Notifications
Client notications support asynchronous delivery of messages to interested subscribers. This enables database clients to register interest in certain queues, and it enables these clients to receive notications when publications on such queues occur. Asynchronous delivery of messages to database clients is in contrast to the traditional polling techniques used to retrieve information.
Publish-Subscribe Concepts
Publish-Subscribe Concepts
This section describes various concepts related to publish-subscribe. queue A queue is an entity that supports the notion of named subjects of interest. Queues can be characterized as: non-persistent queue (lightweight queue) The underlying queue infrastructure pushes the messages published to connected clients in a lightweight, at-best-once, manner. persistent queue Queues serve as durable containers for messages. Messages are delivered in a deferred and reliable mode. agent Publishers and subscribers are internally represented as agents. There is a distinction between an agent and a client. An agent is a persistent logical subscribing entity that expresses interest in a queue through a subscription. An agent has properties, such as an associated subscription, an address, and a delivery mode for messages. In this context, an agent is an electronic proxy for a publisher or subscriber. A client is a transient physical entity. The attributes of a client include the physical process where the client programs run, the node name, and the client application logic. There could be several clients acting on behalf of a single agent. Also, the same client, if authorized, can act on behalf of multiple agents. rule on a queue A rule on a queue is specied as a conditional expression using a predened set of operators on the message format attributes or on the message header attributes. Each queue has an associated message content format that describes the structure of the messages represented by that queue. The message format may be unstructured (RAW) or it may have a well-dened structure (ADT). This allows both subject- or content-based subscriptions.
17-4
Publish-Subscribe Concepts
subscriber Subscribers (agents) may specify subscriptions on a queue using a rule. Subscribers are durable and are stored in a catalog. database event publication framework The database represents a signicant source for publishing information. An event framework is proposed to allow declarative denition of database event publication. As these pre-dened events occur, the framework detects and publishes such events. This allows active delivery of information to end-users in an event-driven manner as part of the publish-subscribe capability. registration Registration is the process of associated delivery information by a given client, acting on behalf of an agent. There is an important distinction between the subscription and registration related to the agent/client separation. Subscription indicates an interest in a particular queue by an agent. It does not specify where and how delivery must occur. Delivery information is a physical property that is associated with a client, and it is a transient manifestation of the logical agent (the subscriber). A specic client process acting on behalf of an agent registers delivery information by associating a host and port, indicating where the delivery should be done, and a callback, indicating how there delivery should be done. publishing a message Publishers publish messages to queues by using the appropriate queuing interfaces. The interfaces may depend on which model the queue is implemented on. For example, an enqueue call represents the publishing of a message. rules engine When a message is posted or published to a given queue, a rules engine extracts the set of candidate rules from all rules dened on that queue that match the published message. subscription services Corresponding to the list of candidate rules on a given queue, the set of subscribers that match the candidate rules can be evaluated. In turn, the set of agents corresponding to this subscription list can be determined and notied.
posting The queue noties all registered clients of the appropriate published messages. This concept is called posting. When the queue needs to notify all interested clients, it posts the message to all registered clients. receive a message A subscriber may receive messages through any of the following mechanisms:
s
A client process acting on behalf of the subscriber species a callback using the registration mechanism. The posting mechanism then asynchronously invokes the callback when a message matches the subscribers subscription. The message content may be passed to the callback function (non-persistent queues only). A client process acting on behalf of the subscriber species a callback using the registration mechanism. The posting mechanism then asynchronously invokes the callback function, but without the full message content. This serves as a notication to the client, which subsequently retrieves the message content in a pull fashion (persistent queues only). A client process acting on behalf of the subscriber simply retrieves messages from the queue in a periodic, or some other appropriate, manner. While the messages are deferred, there is no asynchronous delivery to the end-client.
Scenario: This example shows how system events, client notication, and AQ work together to implement publish-subscribe.
17-6
Create under the user schema, pubsub, with all objects necessary to support a publish-subscribe mechanism. In this particular code, the Agent snoop subscribe to messages that are published at logon events. Note that the user pubsub needs AQ_ADMINISTRATOR_ROLE privileges to use AQ functionalities.
Rem -----------------------------------------------------REM create queue table for persistent multiple consumers: Rem -----------------------------------------------------CONNECT pubsub/pubsub;
Rem Create or replace a queue table BEGIN DBMS_AQADM.CREATE_QUEUE_TABLE( Queue_table => Pubsub.Raw_msg_table, Multiple_consumers => TRUE, Queue_payload_type => RAW, Compatible => 8.1); END; / Rem -----------------------------------------------------Rem Create a persistent queue for publishing messages: Rem -----------------------------------------------------Rem Create a queue for logon events begin BEGIN DBMS_AQADM.CREATE_QUEUE( Queue_name => Pubsub.Logon, Queue_table => Pubsub.Raw_msg_table, Comment => Q for error triggers); END; /
Rem -----------------------------------------------------Rem define new_enqueue for convenience: Rem -----------------------------------------------------CREATE OR REPLACE PROCEDURE New_enqueue( Queue_name IN VARCHAR2, Payload IN RAW , Correlation IN VARCHAR2 := NULL, Exception_queue IN VARCHAR2 := NULL) AS Enq_ct Msg_prop Enq_msgid Userdata DBMS_AQ.Enqueue_options_t; DBMS_AQ.Message_properties_t; RAW(16); RAW(1000);
BEGIN Msg_prop.Exception_queue := Exception_queue; Msg_prop.Correlation := Correlation; Userdata := Payload; DBMS_AQ.ENQUEUE(Queue_name, Enq_ct, Msg_prop, Userdata, Enq_msgid); END; /
-----------------------------------------------------add subscriber with rule based on current user name, using correlation_id ------------------------------------------------------
DECLARE Subscriber Sys.Aq$_agent; BEGIN Subscriber := sys.aq$_agent(SNOOP, NULL, NULL); DBMS_AQADM.ADD_SUBSCRIBER( Queue_name => Pubsub.logon, Subscriber => subscriber, Rule => CORRID = SCOTT ); END; /
17-8
Rem create trigger on after logon: CREATE OR REPLACE TRIGGER pubsub.Systrig2 AFTER LOGON ON DATABASE BEGIN New_enqueue(Pubsub.Logon, HEXTORAW(9999), Dbms_standard.login_user); END; /
s
After subscriptions are created, the next step is for the client to register for notication using callback functions. This is done using the Oracle Call Interface (OCI). The code below performs necessary steps for registration. The initial steps of allocating and initializing session handles are omitted here for sake of clarity.
/***************************************************** Initialize OCI Process/Environment Initialize Server Contexts Connect to Server Set Service Context ******************************************************/ /* Registration Code Begins */
initSubscriptionHn( &subscrhpSnoop, /* subscription handle */ "ADMIN:PUBSUB.SNOOP", /* subscription name */ /* <agent_name>:<queue_name> */ (dvoid*)notifySnoop); /* callback function */
/***************************************************** The Client Process does not need a live Session for Callbacks End Session and Detach from Server ******************************************************/
OCISessionEnd ( svchp, errhp, authp, (ub4) OCI_DEFAULT);
/* detach from server */ OCIServerDetach( srvhp, errhp, OCI_DEFAULT); /* wait for callback */ while (1) sleep(1);
} void initSubscriptionHn (subscrhp, subscriptionName, func) OCISubscription **subscrhp; char* subscriptionName; dvoid * func; {
Now, if user SCOTT logged on to the database, the client is notied, and the call back function notifySnoop is called.
17-11
Part V
Developing Specialized Applications
This part deals with application development scenarios that not every developer faces. Oracle provides a range of features to help with each kind of application. This part contains:
s
Chapter 18, "Developing Web Applications with PL/SQL" Chapter 19, "Porting Non-Oracle Applications to Oracle9i" Chapter 20, "Working with Transaction Monitors with Oracle XA"
18
Developing Web Applications with PL/SQL
If you think that only new languages such as Java and Javascript can do network operations and produce dynamic web content, think again. PL/SQL has a number of features that you can use to web-enable your database and make your back-ofce data interactive and accessible to intranet users or your customers. This chapter discusses the following topics:
s
What Is a PL/SQL Web Application? How Do I Generate HTML Output from PL/SQL? How Do I Pass Parameters to a PL/SQL Web Application? Performing Network Operations within PL/SQL Stored Procedures Embedding PL/SQL Code in Web Pages (PL/SQL Server Pages)
Visiting a web page, following a hypertext link, or pressing a Submit button on an HTML form causes the database server to run a stored procedure. Any choices that a user makes on an HTML form are passed as parameters to the stored procedure. Parameters can also be hardcoded in the URL used to invoke the stored procedure. The results of the stored procedure are printed as tagged HTML text and are displayed in the browser as a web page. Web pages generated this way are dynamic: code runs inside the database server, producing HTML that varies depending on the database contents and the input parameters.
This kind of dynamic content is different from dynamic HTML (DHTML). With DHTML, the code is downloaded as Javascript or some other scripting language, and processed by the browser along with the HTML. A PL/SQL web application can print Javascript or other script code in its output, to produce complex DHTML that would be tedious to produce manually.
s
The dynamic pages can contain links and HTML forms that call more stored procedures, to drill down or perform some other operation on the displayed data. The set of interlinked HTML pages forms the user interface of the web application. There are many techniques for coding dynamic pages, but PL/SQL is especially good for producing dynamic pages based on database processing. Its support for DML statements, dynamic SQL, cursors, and tight server integration provide both power and exibility for web applications. Producing dynamic content using PL/SQL stored procedures gives you the exibility and interactive behavior of CGI programs, without the memory overhead of forking a new CGI process each time. A typical stored procedure might print some header information, issue a query, and loop through the result set to format the data in an HTML list or table. This program ow is very similar to a Perl script that operates on a text le.
18-2
You can learn the API calls corresponding to each tag, or just use some of the basic ones like HTP.PRINT to print the text and tags together:
htp.print(<html>); htp.print(<head>); htp.print('<meta http-equiv="Content-Type" content="text/html">'); htp.print('<title>Title of the HTML File</title>'); htp.print(</head>); htp.print(<body TEXT="#000000" BGCOLOR="#FFFFFF">'); htp.print('<h1>Heading in the HTML File</h1>'); htp.print(<p>Some text in the HTML file.); htp.print(</body>); htp.print(</html>);
This chapter introduces an additional method, PL/SQL server pages, that lets you build on your knowledge of HTML tags, rather than learning a new set of function calls. In an application written as a set of PL/SQL server pages, you can still use functions from the PL/SQL web toolkit to simplify the processing involved in displaying tables, storing persistent data (cookies), and working with CGI protocol internals.
Using HTML form tags. The user lls in a form on one web page, and all the data and choices are transmitted to a stored procedure when the user clicks the Submit button on the page. Hardcoded in the URL. The user clicks on a link, and a set of predened parameters are transmitted to a stored procedure. Typically, you would include separate links on your web page for all the choices that the user might want.
18-4
BEGIN ... FOR i IN 1..checkboxes.count LOOP htp.print(<p>Checkbox value: || checkboxes(i)); END LOOP; ... END; / show errors;
You might prevent the user from entering alphabetic characters in a numeric entry eld, or from entering characters once a length limit is reached. You might silently remove spaces and dashes from a credit card number if the stored procedure expects the value in that format. You might inform the user immediately when they type a number that is too large, so that they can retype it.
Because you cannot always rely on such validation to succeed, code the stored procedures to deal with these cases anyway. Rather than forcing the user to use the Back button when they enter wrong data, display a single page with an error message and the original form with all the other values lled in. For sensitive information such as passwords, a special form of the entry eld, <INPUT TYPE=PASSWORD>, hides the text as it is typed in. For example, the following procedure accepts two strings as input. The rst time it is called, the user sees a simple form prompting for the input values. When the user submits the information, the same procedure is called again to check if the input is correct. If the input is OK, the procedure processes it. If not, the procedure prompts for new input, lling in the original values for the user.
-- Store a name and associated zip code in the database. CREATE OR REPLACE PROCEDURE associate_name_with_zipcode ( name VARCHAR2 DEFAULT NULL,
zip VARCHAR2 DEFAULT NULL ) AS booktitle VARCHAR2(256); BEGIN -- Both entry fields must contain a value. The zip code must be 6 characters. -- (In a real program you would perform more extensive checking.) IF name IS NOT NULL AND zip IS NOT NULL AND length(zip) = 6 THEN store_name_and_zipcode(name, zip); htp.print('<p>The person ' || name || ' has the zip code ' || zip || '.'); -- If the input was OK, we stop here and the user does not see the form again. RETURN; END IF; -- If some data was entered, but it is not correct, show the error message. IF (name IS NULL AND zip IS NOT NULL) OR (name IS NOT NULL AND zip IS NULL) OR (zip IS NOT NULL AND length(zip) != 6) THEN htp.print('<p><b>Please re-enter the data. Fill in all fields, and use a 6-digit zip code.</b>'); END IF; -- If the user has not entered any data, or entered bad data, prompt for -- input values. -- Make the form call the same procedure to check the input values. htp.formOpen( 'scott.associate_name_with_zipcode', 'GET'); htp.print('<p>Enter your name:</td>'); htp.print('<td valign=center><input type=text name=name value="' || name || '">'); htp.print('<p>Enter your zip code:</td>'); htp.print('<td valign=center><input type=text name=zip value="' || zip || '">'); htp.formSubmit(NULL, 'Submit'); htp.formClose; END; / show errors;
18-6
Sending a "cookie" containing the persistent information to the browser. The browser then sends this same information back to the server when accessing other web pages from the same site. Cookies are set and retrieved through the HTTP headers that are transferred between the browser and the web server before the HTML text of each web page. Storing the information in the database itself, where later stored procedures can retrieve it. This technique involves some extra overhead on the database server, and you must still nd a way to keep track of each user as multiple users access the server at the same time.
Regardless of any validation you do on the client side, always code stored procedures to handle the possibility that some parameters are null:
s
Use a DEFAULT clause in all parameter declarations, to prevent an exception when the stored procedure is called with a missing form parameter. You can set the default to zero for numeric values (when that makes sense), and use DEFAULT NULL when you want to check whether or not the user actually species a value. Before using an input parameter value that has a DEFAULT NULL declaration, check if it is null. Make the procedure generate sensible results even when not all input parameters are specied. You might leave some sections out of a report, or display a text string or image in a report to indicate where parameters were not specied. Provide a way to ll in the missing values and run the stored procedure again, directly from the results page. For example, you could include a link that calls the same stored procedure with an additional parameter, or display the original form with its values lled in as part of the output.
18-8
An alternative way to main state information is to use the Oracle9i Application Server and its mod_ose module, as described in Oracle Servlet Engine Users Guide. This approach lets you store state information in package variables that remain available as a user moves around a Web site.
Control the details of the HTTP session, including header lines, cookies, redirects, proxy servers, IDs and passwords for protected sites, and CGI parameters through the GET or POST methods. Speed up multiple accesses to the same Web site using HTTP 1.1 persistent connections. Construct and interpret URLs for use with UTL_HTTP through the ESCAPE and UNESCAPE functions in the UTL_URL package.
Typically, developers have used Java or Perl to perform these operations; this package lets you do them with PL/SQL.
CREATE OR REPLACE PROCEDURE show_url ( url IN VARCHAR2, username IN VARCHAR2 DEFAULT NULL, password IN VARCHAR2 DEFAULT NULL ) AS req utl_http.req;
resp utl_http.resp; name VARCHAR2(256); value VARCHAR2(1024); data VARCHAR2(255); my_scheme VARCHAR2(256); my_realm VARCHAR2(256); my_proxy BOOLEAN; BEGIN -- When going through a firewall, pass requests through this host. -- Specify sites inside the firewall that dont need the proxy host. utl_http.set_proxy(proxy.my-company.com, corp.my-company.com); -- Ask UTL_HTTP not to raise an exception for 4xx and 5xx status codes, -- rather than just returning the text of the error page. utl_http.set_response_error_check(FALSE); -- Begin retrieving this web page. req := utl_http.begin_request(url); -- Identify ourselves. Some sites serve special pages for particular browsers. utl_http.set_header(req, User-Agent, Mozilla/4.0); -- Specify a user ID and password for pages that require them. IF (username IS NOT NULL) THEN utl_http.set_authentication(req, username, password); END IF; BEGIN -- Now start receiving the HTML text. resp := utl_http.get_response(req); -- Show the status codes and reason phrase of the response. dbms_output.put_line(HTTP response status code: || resp.status_code); dbms_output.put_line(HTTP response reason phrase: || resp.reason_phrase); -- Look for client-side error and report it. IF (resp.status_code >= 400) AND (resp.status_code <= 499) THEN -- Detect whether the page is password protected, and we didnt supply -- the right authorization. IF (resp.status_code = utl_http.HTTP_UNAUTHORIZED) THEN utl_http.get_authentication(resp, my_scheme, my_realm, my_proxy); IF (my_proxy) THEN dbms_output.put_line(Web proxy server is protected.); dbms_output.put(Please supply the required || my_scheme ||
18-11
authentication username/password for realm || my_realm || for the proxy server.); ELSE dbms_output.put_line(Web page || url || is protected.); dbms_output.put(Please supplied the required || my_scheme || authentication username/password for realm || my_realm || for the Web page.); END IF; ELSE dbms_output.put_line(Check the URL.); END IF; utl_http.end_response(resp); RETURN; -- Look for server-side error and report it. ELSIF (resp.status_code >= 500) AND (resp.status_code <= 599) THEN dbms_output.put_line(Check if the Web site is up.); utl_http.end_response(resp); RETURN; END IF; -- The HTTP header lines contain information about cookies, character sets, -- and other data that client and server can use to customize each session. FOR i IN 1..utl_http.get_header_count(resp) LOOP utl_http.get_header(resp, i, name, value); dbms_output.put_line(name || : || value); END LOOP; -- Keep reading lines until no more are left and an exception is raised. LOOP utl_http.read_line(resp, value); dbms_output.put_line(value); END LOOP; EXCEPTION WHEN utl_http.end_of_body THEN utl_http.end_response(resp); END; END; / SET serveroutput ON -- The following URLs illustrate the use of this procedure,
-- but these pages do not actually exist. To test, substitute -- URLs from your own web server. exec show_url(http://www.oracle.com/no-such-page.html) exec show_url(http://www.oracle.com/protected-page.html) exec show_url(http://www.oracle.com/protected-page.html, scott, tiger)
Working with Tables, Image Maps, Cookies, CGI Variables, and More from PL/SQL
Packages for all of these functions are supplied with Oracle8i and higher. You use the packages in combination with any PL/SQL gateway, such as the Oracle Internet Application Server (iAS) and WebDB. You can format the results of a query in an HTML table, produce an image map, set and get HTTP cookies, check the values of CGI variables, and combine other typical web operations with a PL/SQL program. Documentation for these packages is not part of the database documentation library. The location of the documentation depends on the particular application server you are running. To get started with these packages, look at their procedure names and parameters using the SQL*Plus DESCRIBE command:
DESCRIBE HTP; DESCRIBE HTF; DESCRIBE OWA_UTIL;
18-13
The steps to implement a web-based solution using PL/SQL server pages are:
s
Choosing a Software Conguration Writing the Code and Content for the PL/SQL Server Page Loading the PL/SQL Server Page into the Database as a Stored Procedure
By writing an HTML page with embedded PL/SQL code and compiling it as a PL/SQL server page. You may call procedures from the PL/SQL Web Toolkit, but not to generate every line of HTML output. By writing a complete stored procedure that produces HTML by calling the HTP and OWA_* packages in the PL/SQL Web Toolkit.
If you have a large body of HTML, and want to include dynamic content or make it the front end of a database application, use PSP. If you have a large body of PL/SQL code that produces formatted output, you may nd it more convenient to produce HTML tags by changing your print statements to call the HTP package of the PL/SQL Web Toolkit.
What is the fastest and most convenient authoring environment for your group?
s
If most work is done using HTML authoring tools, use PSP. If you use authoring tools that produce PL/SQL code for you, such as the page-building wizards in WebDB, then it might be less convenient to use PSP.
Writing the Code and Content for the PL/SQL Server Page
You can start with an existing web page, or with an existing stored procedure. Either way, with a few additions and changes you can create dynamic web pages that perform database operations and display the results.
In the simplest case, it is nothing more than an HTML le. Compiling it as a PL/SQL server page produces a stored procedure that outputs the exact same HTML le. In the most complex case, it is a PL/SQL procedure that generates all the content of the web page, including the tags for title, body, and headings. In the typical case, it is a mix of HTML (providing the static parts of the page) and PL/SQL (lling in the dynamic content).
The order and placement of the PSP directives and declarations is not signicant in most cases -- only when another le is being included. For ease of maintenance, we recommend placing the directives and declarations together near the beginning of the le.
18-15
The following sections discuss the way to produce various results using the PSP scripting elements. If you are familiar with dynamic HTML and want to start coding right away, you can jump forward to Syntax of PL/SQL Server Page Elements on page 18-21 and "Examples of PL/SQL Server Pages" on page 18-25.
Displaying HTML
The PL/SQL parts of the page are enclosed within special delimiters. All other content is passed along verbatim -- including any whitespace -- to the browser. To display text or HTML tags, write it as you would a typical web page. You do not need to call any output function. Sometimes you might want to display one line of output or another, or change the value of an attribute, based on some condition. You can include IF/THEN logic and variable substitution inside the PSP delimiters, as shown in subsequent sections.
type that the browser or other client program recognizes. Users may have to congure their browsers to recognize some MIME types. Typically, a PL/SQL server page is intended to be displayed in a web browser. It could also be retrieved and interpreted by a program that can make HTTP requests, such as a Java or Perl application.
18-17
part of an IF-THEN-ELSE statement. Any variables declared within DECLARE blocks are only visible to the following BEGIN/END block.
These comments do not appear in the HTML output from the PSP. To create a comment that is visible in the HTML output, place the comment in the HTML portion and use the regular HTML comment syntax:
<!-- Comment text -->
To include a comment inside a PL/SQL block within a PSP, you can use the normal PL/SQL comment syntax. For example, here is part of a PSP le showing several kinds of comments:
18-19
<p>Today we introduce our new model XP-10. <%-This is the project with code name "Secret Project". People viewing the HTML page will not see this comment. --%> <!-Some pictures of the XP-10. People viewing the HTML page will see this comment. --> <% for image_file in (select pathname, width, height, description from image_library where model_num = XP-10) -- Comments interspersed with PL/SQL statements. -- People viewing the HTML page will not see this comment. loop %> <img src="<%= image_file.pathname %>" width=<% image_file.width %> height=<% image_file.height %> alt="<% image_file.description %>"> <br> <% end loop; %>
If you want to print out an entire database table in one operation, you can call the OWA_UTIL.TABLEPRINT or OWA_UTIL.CELLSPRINT procedures from the PL/SQL web toolkit:
<% OWA_UTIL.TABLEPRINT(CTABLE => some_table, CATTRIBUTES => border=2, CCOLUMNS => col1, col2, CCLAUSES => WHERE col1 > 5); %>
htp.tableOpen('border=2'); owa_util.cellsprint( 'select col1, col2 from some_table where col1 > 5'); htp.tableClose;
Page Directive
Species characteristics of the PL/SQL server page:
s
What scripting language it uses. What type of information (MIME type) it produces. What code to run to handle all uncaught exceptions. This might be an HTML le with a friendly message, renamed to a .psp le. You must specify this same le name in the loadpsp command that compiles the main PSP le. You must specify exactly the same name in both the errorPage directive and in the loadpsp command, including any relative path name such as ../include/.
Note that the attribute names contentType and errorPage are case-sensitive. Syntax
<%@ page [language="PL/SQL"] [contentType="content type string"] [errorPage="file.psp"] %>
Procedure Directive
Species the name of the stored procedure produced by the PSP le. By default, the name is the lename without the .psp extension.
18-21
Syntax
<%@ plsql procedure="procedure name" %>
Parameter Directive
Species the name, and optionally the type and default, for each parameter expected by the PSP stored procedure. The parameters are passed using name-value pairs, typically from an HTML form. To specify a default value of a character type, use single quotes around the value, inside the double quotes required by the directive. For example:
<%@ parameter="username" type="varchar2" default="'nobody'" %>
Syntax
<%@ plsql parameter="parameter name" [type="PL/SQL type"] [default="value"] %>
Include Directive
Species the name of a le to be included at a specic point in the PSP le. The le must have an extension other than .psp. It can contain HTML, PSP script elements, or a combination of both. The name resolution and le inclusion happens when the PSP le is loaded into the database as a stored procedure, so any changes to the le after that are not reected when the stored procedure is run. You must specify exactly the same name in both the include directive and in the loadpsp command, including any relative path name such as ../include/. Syntax
<%@ include file="path name" %>
Declaration Block
Declares a set of PL/SQL variables that are visible throughout the page, not just within the next BEGIN/END block. This element typically spans multiple lines, with individual PL/SQL variable declarations ended by semicolons. Syntax
<%! PL/SQL declaration; [ PL/SQL declaration; ] ... %>
Expression Block
Species a single PL/SQL expression, such as a string, arithmetic expression, function call, or combination of those things. The result is substituted as a string at that spot in the HTML page that is produced by the stored procedure. You do not need to end the PL/SQL expression with a semicolon. Syntax
<%= PL/SQL expression %>
Loading the PL/SQL Server Page into the Database as a Stored Procedure
You load one or more PSP les into the database as stored procedures. Each .psp le corresponds to one stored procedure. The pages are compiled and loaded in one step, to speed up the development cycle:
loadpsp [ -replace ] -user username/password[@connect_string] [ include_file_name ... ] [ error_file_name ] psp_file_name ...
To do a "create and replace" on the stored procedures, include the -replace ag. The loader logs on to the database using the specied user name, password, and connect string. The stored procedures are created in the corresponding schema. Include the names of all the include les (whose names do not have the .psp extension) before the names of the PL/SQL server pages (whose names have the .psp extension). Also include the name of the le specied in the errorPage attribute of the page directive. These lenames on the loadpsp command line must
18-23
match exactly the names specied within the PSP include and page directives, including any relative path name such as ../include/. For example:
loadpsp -replace -user scott/tiger@WEBDB banner.inc error.psp display_order.psp
In this example:
s
The stored procedure is created in the database WEBDB. The database is accessed as user scott with password tiger, both to create the stored procedure and when the stored procedure is executed. banner.inc is a le containing boilerplate text and script code, that is included by the .psp le. The inclusion happens when the PSP is loaded into the database, not when the stored procedure is executed. error.psp is a le containing code, text, or both that is processed when an unhandled exception occurs, to present a friendly page rather than an internal error message. display_order.psp contains the main code and text for the web page. By default, the corresponding stored procedure is named DISPLAY_ORDER.
The METHOD=GET format is more convenient for debugging and allows visitors to pass exactly the same paramters when they return to the page through a bookmark. The METHOD=POST format allows a larger volume of parameter data, and is suitable for passing sensitive information that should not be displayed in the URL. (URLs linger on in the browsers history list and in the HTTP headers that are passed to the next-visited page.) It is not practical to bookmark pages that are called this way.
Sample Table
In this example, we use a very small table representing a product catalog. It holds the name of an item, the price, and URLs for a description and picture of the item.
Name ---------PRODUCT PRICE URL PICTURE Type ------------VARCHAR2(100) NUMBER(7,2) VARCHAR2(200) VARCHAR2(200)
18-25
We could adjust the SELECT statement to retrieve only a subset of the rows or columns. We could change the HTML or the location of the expressions to change the appearance of each item, or the order in which the columns are shown. At this early stage, we pick a very simple presentation, a set of list items, to avoid any problems from mismatched or unclosed table tags.
<HEAD><TITLE>Show Contents of Catalog (Raw Form)</TITLE></HEAD> <BODY> <UL> <% for item in (select * from catalog order by price desc) loop %> <LI> Item = <%= item.product %><BR> price = <%= item.price %><BR> URL = <I><%= item.url %></I><BR> picture = <I><%= item.picture %></I> <% end loop; %> </UL> </BODY> </HTML>
Once the previous simple example is working, we can display the contents in a more usable format.
s
We use some HTML tags around certain values for emphasis. Instead of printing the URLs for the description and picture, we plug them into link and image tags so that the reader can see the picture and follow the link.
<%@ page language="PL/SQL" %> <%@ plsql procedure="show_catalog_pretty" %> <HTML> <HEAD><TITLE>Show Contents of Catalog (Better Form)</TITLE></HEAD> <BODY> <UL> <% for item in (select * from catalog order by price desc) loop %> <LI> Item = <A HREF="<%= item.url %>"><%= item.product %></A><BR> price = <BIG><%= item.price %></BIG><BR> <IMG SRC="<%= item.picture %>"> <% end loop; %> </UL> </BODY> </HTML>
18-27
To liven up the page, we can make it accept a minimum price, and present only the items that are more expensive. (Your customers buying criteria may vary.) When the page is displayed in a browser, by default the minimum price is 100 units of the appropriate currency. Later, we will see how to allow the user to pick a minimum price.
<%@ page language="PL/SQL" %> <%@ plsql procedure="show_catalog_partial" %> <%@ plsql parameter="minprice" type="NUMBER" default="100" %> <HTML> <HEAD><TITLE>Show Items Greater Than Specified Price</TITLE></HEAD> <BODY> <P>This report shows the items whose price is greater than <%= minprice %>. <UL> <% for item in (select * from catalog where price > minprice order by price desc) loop %> <LI> Item = <A HREF="<%= item.url %>"><%= item.product %></A><BR> price = <BIG><%= item.price %></BIG><BR> <IMG SRC="<%= item.picture %>"> <% end loop; %> </UL> </BODY> </HTML>
The above technique of ltering results is ne for some applications, such as search results, where users might worry about being overwhelmed by choices. But in a retail situation, you might want to use an alternative technique so that customers can still choose to purchase other items.
s
Intead of ltering the results through a WHERE clause, we can retrieve the entire result set, then take different actions for different returned rows. We can change the HTML to highlight the output that meets their criteria. In this case, we use the background color for an HTML table row. We could also insert a special icon, increase the font size, or use some other technique to call attention to the most important rows. At this point, where we want to present a specic user experience, it becomes worth the trouble to lay out the results in an HTML table.
<%@ page language="PL/SQL" %> <%@ plsql procedure="show_catalog_highlighted" %> <%@ plsql parameter="minprice" type="NUMBER" default="100" %>
<%! color varchar2(7); %> <HTML> <HEAD><TITLE>Show Items Greater Than Specified Price</TITLE></HEAD> <BODY> <P>This report shows all items, highlighting those whose price is greater than <%= minprice %>. <TABLE BORDER> <TR> <TH>Product</TH> <TH>Price</TH> <TH>Picture</TH> </TR> <% for item in (select * from catalog order by price desc) loop if item.price > minprice then color := '#CCCCFF'; else color := '#CCCCCC'; end if; %> <TR BGCOLOR="<%= color %>"> <TD><A HREF="<%= item.url %>"><%= item.product %></A></TD> <TD><BIG><%= item.price %></BIG></TD> <TD><IMG SRC="<%= item.picture %>"></TD> </TR> <% end loop; %> </TABLE> </BODY> </HTML>
18-29
<html> <body> <form method="POST" action="show_catalog_partial"> <p>Enter the minimum price you want to pay: <input type="text" name="minprice"> <input type="submit" value="Submit"> </form> </body> </html>
produce with tools and programming languages. It is part of an HTML le, delimited by <FORM> and </FORM> tags, where someone can make choices and enter data, then transmit those choices to a server-side program using the CGI protocol. To produce a complete application using PSP, you might need to learn the syntax of <INPUT>, <SELECT>, and other HTML tags related to forms.
// Draw a horizontal graph line using a graphic that is stretched // by a scaling factor. function graph(howmuch) { preamble = "<img src='/images/graph_line.gif' height='8' width='" climax = howmuch * 4; denouement = "'> (" + howmuch + ")\n" d.write( preamble + climax + denouement ) } // --> </script> </head> <body text="#000000" bgcolor="#FFFFFF"> <h1>Usage Statistics</h1> <table border=1> <% -- For each day, count how many times each procedure was called. for item in (select trunc(time_stamp) t, count(*) n, procname p from audit_table group by trunc(time_stamp), procname order by trunc(time_stamp) desc, procname) loop -- At the start of each days data, print the date. if item.t != last_timestamp then htp.print('<tr><td colspan=2><font size="+2">'); htp.print(htf.bold(item.t)); htp.print('</font></td></tr>'); last_timestamp := item.t; end if; %> <tr><td><%= item.p %></a>: <td> <!-- Render an image of variable width to represent the data value. --> <script language="JavaScript"> <!-graph(<%= item.n %>) // --> </script> </td> </tr> <% end loop; %>
18-31
Coding this procedure as a regular PL/SQL stored procedure would result in convoluted lines with doubled apostrophes, such as:
htp.print(preamble = "<img src='/images/graph_line.gif' height='8' width='");
The rst step is to get all the PL/SQL syntax and PSP directive syntax right. If you make a mistake here, the le does not compile.
s
Make sure you use semicolons to terminate lines where required. If a value must be quoted, quote it. You might need to enclose a single-quoted value (needed by PL/SQL) inside double quotes (needed by PSP). Mistakes in the PSP directives are usually reported through PL/SQL syntax messages. Check that your directives use the right syntax, that directives are closed properly, and that you are using the right element (declaration, expression, or code block) depending on what goes inside it. PSP attribute names are case-sensitive. Most are specied in all lowercase; contentType and errorPage must be specied as mixed-case.
The next step is to run the PSP le by requesting its URL in a web browser. At this point, you might get an error that the le is not found.
s
Make sure you are requesting the right virtual path, depending on the way the web gateway is congured. Typically, the path includes the hostname, optionally a port number, the schema name, and the name of the stored procedure (with no .psp extension). Remember, if you use the -replace option when compiling the le, the old version of the stored procedure is erased. So, after a failed compilation, you must x the error or the page is not available. You might want to test
new scripts in a separate schema until they are ready, then load them into the production schema.
s
If you copied the le from another le, remember to change any procedure name directives in the source to match the new le name. Once you get one le-not-found error, make sure to request the latest version of the page the next time. The error page might be cached by the browser. You might need to press Shift-Reload in the browser to bypass its cache.
When the PSP script is run, and the results come back to the browser, use standard debugging techniques to check for and correct wrong output. The tricky part is to set up the interface between different HTML forms, scripts, and CGI programs so that all the right values are passed into your page. The page might return an error because of a parameter mismatch.
s
To see exactly what is being passed to your page, use METHOD=GET in the calling form so that the parameters are visible in the URL. Make sure that the form or CGI program that calls your page passes the correct number of parameters, and that the names specied by the NAME= attributes on the form match the parameter names in the PSP le. If the form includes any hidden input elds, or uses the NAME= attribute on the Submit or Reset buttons, the PSP le must declare equivalent parameters. Make sure that the parameters can be cast from string into the correct PL/SQL types. For example, do not include alphabetic characters if the parameter in the PSP le is declared as a NUMBER. Make sure that the URLs query string consists of name-value pairs, separated by equals signs, especially if you are passing parameters by constructing a hardcoded link to the page. If you are passing a lot of parameter data, such as large strings, you might exceed the volume that can be passed with METHOD=GET. You can switch to METHOD=POST in the calling form without changing your PSP le. Although the loadpsp command reports line numbers correctly when there is a syntax error in your source le, line numbers reported for runtime errors refer to a transformed version of the source and dont match the line numbers in the original source. When you encounter errors like these, that produce an error trace instead of the expected web page, you will need to locate the error through exception handlers and by printing debug output.
18-33
Pages can be rendered faster in the browser if the HEIGHT= and WIDTH= attributes are specied for all images. You might standardize on picture sizes, or store the height and width of images in the database along with the data or URL. For viewers who turn off graphics, or who use alternative browsers that read the text out loud, include a description of signicant images using the ALT= attribute. You might store the description in the database along with the image. Although an HTML table provides a good way to display data, a large table can make your application seem slow. Often, the reader sees a blank page until the entire table is downloaded. If the amount of data in an HTML table is large, consider splitting the output into multiple tables. If you set text, font, or background colors, test your application with different combinations of browser color settings:
s
Test what happens if you override just the foreground color in the browser, or just the background color, or both. Generally, if you set one color (such as the foreground text color), you should set all the colors through the <BODY> tag, to avoid hard-to-read combinations like white text on a white background. If you use a background image, specify a similar background color to provide proper contrast for viewers who do not load graphics. If the information conveyed by different colors is crucial, consider using some other method instead of or in addition to the color change. For example, you might put a graphic icon next to special items in a table. Some of your viewers may see your page on a monochrome screen, or on browsers that cannot represent different colors. (Such browsers might t in a shirt pocket and use a stylus for input.)
Providing context information prevents users from getting lost. Include a descriptive <TITLE> tag for your page. If the user is partway through a procedure, indicate which step is represented by your page. Provide links to logical points to continue with the procedure, return to a previous step, or cancel the procedure completely. Many pages might use a standard set of links that you embed using the include directive.
In any entry elds, users might enter incorrect values. Where possible, use select lists to present a set of choices. Validate any text entered in a eld before passing it to SQL. The earlier you can validate, the better; a Javascript routine can detect incorrect data and prompt the user to correct it before they press the Submit button and make a call to the database. Browsers tend to be lenient when displaying incorrect HTML. But what looks OK in one browser might look bad or might not display at all in another browser.
s
Pay attention to HTML rules for quotation marks, closing tags, and especially for anything to do with tables. Minimize the dependence on tags that are only supported by a single browser. Sometimes you can provide an extra bonus using such tags, but your application should still be usable with other browsers. You can check the validity, and even in some cases the usability, of your HTML for free at many sites on the World Wide Web.
18-35
19
Porting Non-Oracle Applications to Oracle9i
Often, a programming project requires adapting existing code rather than writing new code. When that code comes from some other database platform, it is important to understand the Oracle features that are designed to make porting easy. Topics include the following:
s
The standard notation makes the relations between the tables explicit, and saves you from coding equality tests for join conditions in the WHERE clause. Support for full outer joins also eliminates the need for complex workarounds to do those queries. Because different vendors support varying amounts of standard join syntax, and some vendors introduce their own syntax extensions, you might still need to rewrite some join queries. See Oracle9i SQL Reference for full syntax of the SELECT statement and the support for join notation.
Is There an Automated Way to Migrate a Schema and Associated Data from Another Database System?
Yes. Oracle provides a free product called the Oracle Migration Workbench that can convert a schema (including data, triggers, and stored procedures) from other database products to Oracle8 and Oracle8i. Although the product itself runs on Windows, it can transfer data from databases on other operating systems, to Oracle databases running on any operating systems. By using this product, you can avoid having to write your own applications to convert your legacy data when switching to Oracle8i. Related technology lets you convert certain kinds of source code, for example to migrate Visual Basic code to Java. At the time of this publication, migration is supported from the following databases:
19-2
MS SQL Server 6.5 MS SQL Server 7.0 MS Access 2.0 MS Access 95 MS Access 97 Sybase Adaptive Server 11 MySQL 3.22
For the current set of supported databases, see the Web site: http://otn.oracle.com/tech/migration/
This technique helps performance when you can replace a call to a PL/SQL function with a test done directly in SQL. Oracle8i supports the SQL-92 notation for searched case, simple case, NULLIF, and COALESCE.
s
Saturday, weekend, Sunday, weekend, unknown day) INTO day_category FROM DUAL;
This construct lets you test a variable against a number of different alternatives, and return a different value in each case. The nal value is used when none of the alternatives is matched. The CASE technique is more portable, and is preferable for new code.
19-4
20
Working with Transaction Monitors with Oracle XA
This chapter describes how to use the Oracle XA library, which is typically used in applications that work with transaction monitors. The XA features are most useful in applications where transactions interact with more than one database. The Oracle XA library is an external interface that allows global transactions to be coordinated by a transaction manager other than the Oracle server. This allows inclusion of non-Oracle entities called resource managers (RM) in distributed transactions. The Oracle XA library conforms to the X/Open Distributed Transaction Processing (DTP) software architectures XA interface specication. The chapter includes the following topics:
s
X/Open Distributed Transaction Processing (DTP) XA and the Two-Phase Commit Protocol Transaction Processing Monitors (TPMs) Support for Dynamic and Static Registration Oracle XA Library Interface Subroutines Developing and Installing Applications That Use the XA Libraries Troubleshooting XA Applications XA Issues and Restrictions Changes to Oracle XA Support
20-1
See Also:
s
For a general overview of XA, including basic architecture, see X/Open CAE Specication - Distributed Transaction Processing: The XA Specication. You can obtain a copy of this document by requesting X/Open Document No. XO/CAE/91/300 or ISBN 1 872630 24 3 from: X/Open Company, Ltd., 1010 El Camino Real, Suite 380, Menlo Park, CA 94025, U.S.A.
For background and reference information about the Oracle XA library, see Oracle Call Interface Programmers Guide. For information on library linking lenames, see the Oracle operating system-specic documentation. A README.doc le is located in a directory specied in the Oracle operating system-specic documentation and describes changes, bugs, or restrictions in the Oracle XA library for your platform since the last version.
20-2
A TM is usually a component provided by a transaction processing monitor (TPM) vendor. The TM assigns identiers to transactions, and monitors and coordinates their progress. It uses Oracle XA library subroutines to tell Oracle how to process the transaction, based on its knowledge of all RMs in the transaction. You can nd a list of the XA subroutines and their descriptions later in this section. An application program (AP) denes transaction boundaries and species actions that constitute a transaction. For example, an AP can be a precompiler or OCI program. The AP operates on the RMs resource through the RMs native interface, for example SQL. However, it starts and completes all transaction operations through the transaction manager through an interface called TX. The AP itself does not directly use the XA interface
20-3
Figure 201
Oracle
Other Resources
20-4
subroutines are vendor-specic, and may differ from those used here. For example, you may nd that the tx_open call is referred to as tp_open on your system. To check terminology, see the documentation supplied with the transaction processing monitor.
xa_switch_t structures
The Oracle Server xa_switch_t structure name for static registration is xaosw. The Oracle Server xa_switch_t structure name for dynamic registration is xaoswd. These structures contain entry points and other information for the resource manager. The Oracle Server resource manager name within the xa_switch_t structure is Oracle_XA. The close string used by xa_close() is ignored and is allowed to be null. The format of the open string used by xa_open() is described in detail in "Dening the xa_open String" on page 20-10. Libraries needed to link applications using Oracle XA have operating system-specic names. It is similar to linking an ordinary precompiler or OCI program except you may have to link any TPM-specic libraries. If you are not using sqllib, then be sure to link with $ORACLE_HOME/lib/xaonsl.o. None. The functionality to support XA is part of both Standard Edition and Enterprise Edition.
libraries
requirements
20-5
In phase one, the prepare phase, the TM asks each RM to guarantee the ability to commit any part of the transaction. If this is possible, then the RM records its prepared state and replies afrmatively to the TM. If it is not possible, then the RM may roll back any work, reply negatively to the TM, and forget any knowledge about the transaction. The protocol allows the application, or any RM, to roll back the transaction unilaterally until the prepare phase is complete. In phase two, the commit phase, the TM records the commit decision. Then the TM issues a commit or rollback to all RMs which are participating in the transaction.
Note: TM can issue a commit for an RM only if all RMs have
20-6
Starting a new transaction and associating it with an ID Rolling back a transaction Preparing and committing a transaction
XA Library Subroutines
The following XA Library subroutines are available:
XA Subroutine Description
Connects to the resource manager. Disconnects from the resource manager. Starts a new transaction and associate it with the given transaction ID (XID), or associates the process with an existing transaction. Disassociates the process from the given XID. Rolls back the transaction associated with the given XID. Prepares the transaction associated with the given XID. This is the rst phase of the two-phase commit protocol. Commits the transaction associated with the given XID. This is the second phase of the two-phase commit protocol. Retrieves a list of prepared, heuristically committed or heuristically rolled back transaction.
xa_recover
20-7
XA Subroutine
Description
xa_forget
In general, the AP does not need to worry about these subroutines except to understand the role played by the xa_open string.
OCISvcCtx *xaoSvcCtx(text *dbname): This function returns the OCI service handle for a given XA connection. The dbname parameter must be the same as the dbname parameter passed in the xa_open string. OCI applications can use this routing instead of the sqlld2 calls to obtain the connection handle. Hence, OCI applications need not link with the SQLLIB library. The service handle can be converted to the Version 7 OCI logon data area (LDA) using OCISvcCtxToLda() [Version 8 OCI]. Client applications must remember to convert the Version 7 LDA to a service handle using OCILdaToSvcCtx() after completing the OCI calls.
2.
OCIEnv *xaoEnv(text *dbname): This function returns the OCI environment handle for a given XA connection. The dbname parameter must be the same as the dbname parameter passed in the xa_open string.
3.
int xaosterr(OCISvcCtx *SvcCtx, sb4 error): This function, only applicable to dynamic registration, converts an Oracle error code to an XA error code. The rst parameter is the service handle used to execute the work in the database. The second parameter is the error code that was returned from Oracle. Use this function to determine if the error returned from an OCI command was caused because the xa_start failed. The function returns XA_OK if the error was not generated by the XA module and a valid XA error if the error was generated by the XA module.
20-8
Responsibilities of the DBA or System Administrator on page 20-9 Responsibilities of the Application Developer on page 20-10 Dening the xa_open String on page 20-10 Interfacing XA with Precompilers and OCIs on page 20-17 Transaction Control using XA on page 20-20 Migrating Precompiler or OCI Applications to TPM Applications on page 20-23 XA Library Thread Safety on page 20-24
Dene the open string with the application developers help. This is described in "Dening the xa_open String" on page 20-10.
2.
For Oracle Server Release 8.0: Grant the select privilege to the DBA_PENDING_TRANSACTIONS view for all Oracle Server user(s) specied in the xa_open string. For Oracle Server Release 7.3: Make sure V$XATRANS$ exists. This view should have been created during the XA library installation. You can manually create the view, if needed, by running the SQL script XAVIEW.SQL. This SQL script should be executed as the Oracle user SYS. Grant the SELECT privilege to the V$XATRANS$ view for all Oracle Server accounts which will be used by Oracle XA library applications.
See Also: Your Oracle operating system-specic documentation
Install the resource manager, using the open string information, into the TPM conguration, following the TPM vendor instructions.
20-9
The DBA or system administrator should be aware that a TPM system starts the process that connects to an Oracle database server. See your TPM documentation to determine what environment exists for the process and what user ID it will have. Be sure that correct values are set for ORACLE_HOME and ORACLE_SID.
Next, grant the user ID write permission to the directory in which the XA trace le will be written.
information on how to specify a sid or a trace directory that is different from the defaults. Also be sure to grant the user the SELECT privilege on DBA_PENDING_TRANSACTIONS.
4.
Start up the relevant databases to bring Oracle XA applications on-line. This should be done before starting any TPM servers.
Dene the open string with the DBA or system administrators help. Dening the open string is described later in this section.
2.
Develop the applications. Observe special restrictions on transaction-oriented SQL statements for precompilers.
See Also: "Interfacing XA with Precompilers and OCIs" on
page 20-17
3.
Optional Fields
where required_elds are: Acc=P// Or Acc=P/user/password SesTm=session_time_limit and where optional_elds are: DB=db_name LogDir=log_dir MaxCur=maximum_#_of_open_cursors Objects=true/false SqlNet=connect_string Loose_Coupling=true/false SesWt=session_wait_limit Threads=true/false
Note:
s
You can enter the required elds and optional elds in any order when constructing the open string. All eld names are case insensitive. Their values may or may not be case-sensitive depending on the platform. There is no way to use the "+" character as part of the actual information string.
Required Fields
Required elds for the open string are described in this section. Acc=P//
20-11
or Acc=P/user/password
Syntax Element Description
Acc P P//
Species user access information Indicates that explicit user and password information is provided. Indicates that no explicit user or password information is provided, and that the operating system authentication form will be used. For more information see Oracle9i Database Administrators Guide.
user password
For example, Acc=P/scott/tiger indicates that user and password information is provided. In this case, the user is scott and the password is tiger. As previously mentioned, make sure that scott has the SELECT privilege on the DBA_PENDING_TRANSACTIONS table. Acc=P// indicates that no user or password information is provided, thus defaulting to operating system authentication. SesTm=session_time_limit
Syntax Element Description
SesTm
Species the maximum length of time a transaction can be inactive before it is automatically aborted by the system.
Syntax Element
Description
session_time_limit
This value should be the maximum time allowed in a transaction between one service and the next, or a service and the commit or rollback of the transaction. For example, if the TPM uses remote procedure calls between the client and the servers, then SesTM applies to the time between the completion of one RPC and the initiation of the next RPC, or the tx_commit, or the tx_rollback. The unit for this time limit is in seconds. The value of 0 indicates no limit. For example, SesTM=15 indicates that the session idle time limit is 15 seconds. Entering a value of 0 is strongly discouraged. It might tie up resources for a long time if something goes wrong. Also, if a child process has SesTM=0, the SesTM setting is not effective after the parent process is terminated.
Optional Fields
Optional elds are described below. DB=db_name
Syntax Element Description
DB
20-13
Syntax Element
Description
db_name
Indicates the name used by Oracle precompilers to identify the database. Application programs that use only the default database for the Oracle precompiler (that is, they do not use the AT clause in their SQL statements) should omit the DB=db_name clause in the open string. Applications that use explicitly named databases should indicate that database name in their DB=db_name field. Version 7 OCI programs need to call the sqlld2() function to obtain the correct lda_def, which is the equivalent of a service context. Version 8 OCI programs need to call the xaoSvcCtx function to get the OCISvcCtx service context. The db_name is not the sid and is not used to locate the database to be opened. Rather, it correlates the database opened by this open string with the name used in the application program to execute SQL statements. The sid is set from either the environment variable ORACLE_SID of the TPM application server or the sid given in the Oracle Net (formerly SQL*Net and Net8) clause in the open string. The Oracle Net clause is described later in this section. Some TPM vendors provide a way to name a group of servers that use the same open string. The DBA may nd it convenient to choose the same name both for that purpose and for db_name.
For example, DB=payroll indicates that the database name is "payroll", and that the application server program will use that name in AT clauses. LogDir=log_dir
Syntax Element Description
LogDir
Species the directory on a local machine where the Oracle XA library error and tracing information may be logged.
Syntax Element
Description
log_dir
Indicates the path name of the directory where the tracing information should be stored. The default is $ORACLE_HOME/rdbms/log if ORACLE_HOME is set; otherwise, it is the current directory.
For example, LogDir=/xa_trace indicates that the error and tracing information is located under the /xa_trace directory.
Note: Ensure that the directory you specify for logging exists and
the application server can write to it. Loose_Coupling=true/false See "Transaction Branches" on page 20-31 for a complete explanation. Objects=true/false
Syntax Element Description
Objects true/false
Species whether the application is process is initialized in object mode. The default value is False. If the application needs to use certain API calls that require object mode, such as OCIAssignRawbytes(), then set the value to true.
MaxCur=maximum_#_of_open_cursors
Syntax Element Description
MaxCur
Species the number of cursors to be allocated when the database is opened. It serves the same purpose as the precompiler option maxopencursors. Indicates the number of open cursors to be cached.
maximum_#_of_ open_cursors
20-15
For example, MaxCur=5 indicates that the precompiler should try to keep five open cursors cached.
Note: This parameter overrides the precompiler option
maxopencursors that you might have specified in your source code or at compile time.
SqlNet=db_link
Syntax Element Description
SqlNet db_link
Species the Oracle Net (formerly, SQL*Net and Net8) database link. Indicates the string to use to log on to the system. The syntax for this string is the same as that used to set the TWO-TASK environment variable.
For example, SqlNet=hqfin@NEWDB indicates the database with sid=NEWDB accessed at host hqfin by TCP/IP. The SqlNet parameter can be used to specify the ORACLE_SID in cases where you cannot control the server environment variable. It must also be used when the server needs to access more than one Oracle Server database. To use the Oracle Net string without actually accessing a remote database, use the Pipe driver. For example:
SqlNet=localsid1
localsid1 is an alias dened in the tnsnames.ora le. Make sure that all databases to be accessed with a Oracle Net database link have an entry in /etc/oratab.
SesWt=session_wait_limit
Syntax Element
Description
SesWt
Species the time-out limit when waiting for a transaction branch that is being used by another session. The default value is 60 seconds. The number of seconds Oracle waits before XA_RETRY is returned.
session_wait_limit
Threads=true/false
Syntax Element Description
Threads true/false
Species whether the application is multi-threaded. The default value is False. If the application is multi-threaded, then the setting is true.
Using precompilers with the default database Using precompilers with a named database
20-17
indicates the default connection, and only one default connection is allowed for each process. The following is an example of an open string identifying a default Pro*C/C++ connection.
ORACLE_XA+SqlNet=host@MAIL+ACC=P/scott/tiger +SesTM=10+LogDir=/usr/local/logs
Note that the DB=db_name is absent, indicating an empty database ID string. The syntax of a SQL statement would be:
EXEC SQL UPDATE Emp_tab SET Sal = Sal*1.5;
Note that there is no DB=db_name eld in the last open string. In the application server program, you would enter declarations, such as:
EXEC SQL DECLARE PAYROLL DATABASE; EXEC SQL DECLARE MANAGERS DATABASE;
Again, the default connection (corresponding to the third open string that does not contain the db_name eld) needs no declaration. When doing the update, you would enter statements similar to the following:
EXEC SQL AT PAYROLL UPDATE Emp_Tab SET Sal=4500 WHERE Empno=7788;
EXEC SQL AT MANAGERS UPDATE Emp_Tab SET Mgr=7566 WHERE Empno=7788; EXEC SQL UPDATE Emp_Tab SET Deptno=30 WHERE Empno=7788;
There is no AT clause in the last statement because it is referring to the default database. In Oracle precompilers release 1.5.3 or later, you can use a character host variable in the AT clause, as the following example shows:
EXEC SQL BEGIN DECLARE SECTION; DB_NAME1 CHARACTER(10); DB_NAME2 CHARACTER(10); EXEC SQL END DECLARE SECTION; ... SET DB_NAME1 = PAYROLL SET DB_NAME2 = MANAGERS ... EXEC SQL AT :DB_NAME1 UPDATE... EXEC SQL AT :DB_NAME2 UPDATE...
create connections. Any work performed would be outside the global transaction and would have to be committed separately.
20-19
This obtains the lda for this resource manager. Release 8.0 If DB=db_name is not present in the open string, then execute:
xaoSvcCtx(NULL);
This gets the server context for this resource manager. In the same way, you can execute:
xaoEnv(NULL);
or:
xaoEnv(db_name);
Oracle Call Interface Programmers Guide has more information about using the OCISvcCtx.
tx_open
TX Function
Description
Logs out of the resource manager(s) Starts a new transaction Commits a transaction Rolls back the transaction
Most TPM applications are written using a client/server architecture where an application client requests services and an application server provides services. The examples that follow use such a client/server model. A service is a logical unit of work, which in the case of the Oracle Server as the resource manager, comprises a set of SQL statements that perform a related unit of work. For example, when a service named "credit" receives an account number and the amount to be credited, it executes SQL statements to update information in certain tables in the database. In addition, a service might request other services. For example, a "transfer fund" service might request services from a "credit" and "debit" service. Usually application clients request services from the application servers to perform tasks within a transaction. However, for some TPM systems, the application client itself can offer its own local services. You can encode transaction control statements within either the client or the server; as shown in the examples. To have more than one process participating in the same transaction, the TPM provides a communication API that allows transaction information to ow between the participating processes. Examples of communications APIs include RPC, pseudo-RPC functions, and send/receive functions. Because the leading vendors support different communication functions, the examples that follow use the communication pseudo-function tpm_service to generalize the communications API. X/Open has included several alternative methods for providing communication functions in their preliminary specication. At least one of these alternatives is supported by each of the leading TPM vendors.
20-21
/*Request Service*/
Server:
ServiceName() { <get service specific data> tx_begin(); EXEC SQL UPDATE ....;
/*This application server temporarily becomes*/ /*a client and requests another service.*/ tpm_service("AnotherService"); tx_commit(); /*Commit the transaction*/ <return service status back to the client> }
Server:
Service1() { <get service specific data> EXEC SQL UPDATE ....; <return service status back to the client>
} Service2() { <get service specific data> EXEC SQL UPDATE ....; ... <return service status back to client> }
Reorganize the application into a framework of "services". This means that application clients request services from application servers. Some TPMs require the application to use the tx_open and tx_close functions, whereas other TPMs do the logon and logoff implicitly. If you do not specify the sqlnet parameter in your open string, then the application uses the default Oracle Net driver. Thus, you must be sure that the application server is brought up with the ORACLE_HOME and ORACLE_SID environment variables properly dened. This is accomplished in a TPM-specic fashion. See your TPM vendor documentation for instructions on how to accomplish this.
2.
Ensure that the application replaces the regular connect and disconnect statements. For example, replace the connect statements EXEC SQL CONNECT (for precompilers) or OCISessionBegin() (for OCIs) by tx_open(). Replace the disconnect statements EXEC SQL COMMIT/ROLLBACK RELEASE WORK (for precompilers), or OCISessionEnd() (for OCIs) by tx_close(). The V7 equivalent for OCISessionBegin() was olon() and for OCISessionEnd(), ologof().
3.
Ensure that the application replaces the regular commit/rollback statements and begins the transaction explicitly. For example, replace the commit/rollback statements EXEC SQL COMMIT/ROLLBACK WORK (for precompilers), or ocom()/orol() (for OCIs) by tx_commit()/tx_rollback() and start the transaction by calling tx_begin().
20-23
4.
Ensure that the application resets the fetch state prior to ending a transaction. In general, release_cursor=no should be used. Use release_cursor=yes only when you are certain that a statement will be executed only once.
Table 201 lists the TPM functions that replace regular Oracle commands when migrating precompiler or OCI applications to TPM applications.
Table 201 TPM Replacement Commands
Regular Oracle Commands TPM Functions CONNECT user/password implicit start of transaction SQL COMMIT ROLLBACK disconnect SET TRANSACTION READ ONLY tx_open (possibly implicit) tx_begin Service that executes the SQL tx_commit tx_rollback tx_close (possibly implicit) Not allowed
Troubleshooting XA Applications
establishes a connection, only that thread can use that connection. No other thread can make a call on that connection.
Restrictions on Threading in XA
The following restrictions apply when using threads:
s
Any Pro* or OCI code that executes as part of the application server process on the transaction monitor cannot be threaded unless the transaction monitor is explicitly told when each new application thread is started. This is typically accomplished by using a special C compiler provided by the transaction monitor vendor. The Pro* statements, EXEC SQL ALLOCATE and EXEC SQL USE are not supported. Therefore, when threading is enabled, embedded SQL statements cannot be used across non-XA connections. If one thread in a process connects to Oracle through XA, all other threads in the process that connect to Oracle must also connect through XA. You cannot connect through EXEC SQL in one thread and through XA in another thread.
Troubleshooting XA Applications
This section discusses how to nd information in case of problems or system failure. It also discusses trace les and recovery of pending transactions.
20-25
Troubleshooting XA Applications
XA Trace Files
The Oracle XA library logs any error and tracing information to its trace le. This information is useful in supplementing the XA error codes. For example, it can indicate whether an xa_open failure is caused by an incorrect open string, failure to nd the Oracle Server instance, or a logon authorization failure. The name of the trace le is: xa_db_namedate.trc where db_name is the database name you specied in the open string eld DB=db_name, and date is the date when the information is logged to the trace le. If you do not specify DB=db_name in the open string, then it automatically defaults to the name NULL.
0x1 Trace the entry and exit to each procedure in the XA interface. This can be useful in seeing exactly what XA calls the TP Monitor is making and what transaction identier it is generating. 0x2 Trace the entry to and exit from other non-public XA library routines. This is generally of use only to Oracle developers. 0x4 Trace various other "interesting" calls made by the XA library, such as specic calls to the Oracle Call Interface. This is generally of use only to Oracle developers.
The trace le can be created in the LogDir directory as specied in the open string. If you do not specify LogDir in the open string, then the Oracle XA application attempts to create the trace le in the $ORACLE_HOME/rdbms/log directory, if it can determine where $ORACLE_HOME is located.
Troubleshooting XA Applications
If the Oracle XA application cannot determine where $ORACLE_HOME is located, then the trace le is created in the current working directory.
same DB eld and LogDir eld in their open strings log all trace information that occurs on the same day to the same trace le. Each entry in the trace le contains information that looks like this:
1032.12345.2: ORA-01017: invalid username/password; logon denied 1032.12345.2: xaolgn: XAER_INVAL; logon denied
Where "1032" is the time when the information is logged, "12345" is the process ID (PID), "2" is the resource manager ID, xaolgn is the module name, XAER_INVAL was the error returned as specied in the XA standard, and ORA-1017 is the Oracle Server information that was returned.
Locking data that is required by other transactions Not resolved in a reasonable amount of time
20-27
For more information about overriding in-doubt transactions in the circumstances described above, or about how to decide whether the in-doubt transaction should be committed or rolled back, see the TPM documentation.
The DBID column is always xa_orcl The DBUSER_OWNER column is always db_namexa.oracle.com
Remember that the db_name is always specied as DB=db_name in the open string. If you do not specify this eld in the open string, then the value of this column is NULLxa.oracle.com for transactions generated by Oracle XA applications. For example, you could use the SQL statement below to obtain more information about in-doubt transactions generated by Oracle XA applications.
SELECT * FROM Dba_2pc_pending p, Dba_2pc_neighbors n WHERE p.Local_tran_id = n.Local_tran_id AND n.Dbid = xa_orcl;
Alternatively, if you know the format ID used by the transaction processing monitor, then you can use DBA_PENDING_TRANSACTIONS or V$GLOBAL_TRANSACTIONS. While DBA_PENDING_TRANSACTIONS gives a list of both active and failed prepared transactions, V$GLOBAL_TRANSACTIONS gives a list of all active global transactions.
This means that the transaction processing monitors (TPMs) use shared servers to open the connection to Oracle. The operating system network connection required for the database link is opened by the dispatcher, instead of the Oracle server process. Thus, when a particular service or RPC completes, the transaction can be detached from the server so that it can be used by other services or RPCs.
s
Access to the other database must use SQL*Net Version 2, Net8, or Oracle Net. The other database being accessed should be another Oracle Server database.
Assuming that these restrictions are satised, Oracle Server allows such links and propagates the transaction protocol (prepare, rollback, and commit) to the other Oracle Server databases.
Caution: If these restrictions are not satised, then when you
use database links within an XA transaction, it creates an O/S network connection in the Oracle Server that is connected to the TPM server process. Because this O/S network connection cannot be moved from one process to another, you cannot detach from this server. When you access a database through a database link, you receive an ORA#24777 error. If using the shared server conguration is not possible, then access the remote database through the Pro*C/C++ application using EXEC SQL AT syntax. The parameter open_links_per_instance species the number of migratable open database link connections. These dblink connections are used by XA transactions so that the connections are cached after a transaction is committed. Another transaction is free to use the dblink connection provided the user that created the connection is the same as the user who created the transaction. This parameter is different from the open_links parameter, which is the number of dblink connections from a session. The open_links parameter is not applicable to XA applications.
20-29
SQL-Based Restrictions
Rollbacks and Commits Because the transaction manager is responsible for coordinating and monitoring the progress of the global transaction, the application should not contain any Oracle Server-specic statement that independently rolls back or commits a global transaction. However, you can use rollbacks and commits in a local transaction. Do not use EXEC SQL ROLLBACK WORK for precompiler applications when you are in the middle of a global transaction. Similarly, an OCI application should not execute OCITransRollback(), or the Version 7 equivalent orol(). You can roll back a global transaction by calling tx_rollback(). Similarly, a precompiler application should not have the EXEC SQL COMMIT WORK statement in the middle of a global transaction. An OCI application should not execute OCITransCommit() or the Version 7 equivalent ocom(). Instead, use tx_commit() or tx_rollback() to end a global transaction. DDL Statements Because a DDL SQL statement, such as CREATE TABLE, implies an implicit commit, the Oracle XA application cannot execute any DDL SQL statements. Session State Oracle does not guarantee that session state will be valid between services. For example, if a service updates a session variable (such as a global package variable), then another service that executes as part of the same global transaction may not see the change. Use savepoints only within a service. The application must not refer to a savepoint that was created in another service. Similarly, an application must not attempt to fetch from a cursor that was executed in another service. SET TRANSACTION Do not use the SET TRANSACTION READ ONLY | READ WRITE | USE ROLLBACK SEGMENT SQL statement. Connecting or Disconnecting with EXEC SQL Do not use the EXEC SQL command to connect or disconnect. That is, do not use EXEC SQL COMMIT WORK RELEASE or EXEC SQL ROLLBACK WORK RELEASE.
Transaction Branches
Oracle Server transaction branches within the same global transaction can share locks in either a tightly or loosely coupled manner. However, if the branches are on different instances when running Oracle Real Application Clusters, then they will be loosely coupled. In tightly coupled transaction branches, the locks are shared between the transaction branches. This means that updates performed in one transaction branch can be seen in other branches that belong to the same global transaction before the update is committed. The Oracle Server obtains the DX lock before executing any statement in a tightly coupled branch. Hence, the advantage of using loosely coupled transaction branches is that there is more concurrency (because a lock is not obtained before the statement is executed). The disadvantage is that all the transaction branches must go through the two phases of commit, that is, XA one phase optimization cannot be used. These trade-offs between tightly coupled branches and loosely coupled branches are illustrated in Table 202.
.
Association Migration
The Oracle Server does not support association migration (a means whereby a transaction manager may resume a suspended branch association in another branch).
Asynchronous Calls
The optional XA feature asynchronous XA calls is not supported.
Initialization Parameters
Set the transactions init.ora parameter to the expected number of concurrent global transactions. The parameter open_links_per_instance species the number of migratable open database link connections. These dblink connections are used by XA transactions so that the connections are cached after a transaction is committed.
20-31
Installation
No scripts need be executed to use XA. It is necessary, however, to run the xaview.sql script to run Release 7.3 applications with the Oracle8 or later server. Grant the SELECT privilege on SYS.DBA_PENDING_TRANSACTIONS to all users that connect to Oracle through the XA interface.
Library Compatibility
The XA library supplied with Release 7.3 can be used with a Release 8.0 or later Oracle Server. You must use the Release 7.2 XA library with a Release 7.2 Oracle Server. You can use the 8.0 library with a Release 7.3 Oracle Server. There is only one case of backward compatibility: an XA application that uses Release 8.0 OCI works with a Release 7.3 Oracle Server, but only if you use sqlld2 and obtain an lda_def before executing SQL statements. Client applications must remember to convert the Version 7 LDA to a service handle using OCILdaToSvcCtx() after completing the OCI calls. Oracle8 and does not support 7.1.6 XA calls (although it does support 7.3 XA calls). Thus, 7.1.6 XA calls need to relink Tuxedo applications with Oracle8 XA libraries.
Session Caching Is No Longer Needed Dynamic Registration Is Supported Loosely Coupled Transaction Branches Are Supported SQLLIB Is Not Needed for OCI Applications No Installation Script Is Needed to Run XA The XA Library Can Be Used with the Oracle Real Application Clusters Option on All Platforms Transaction Recovery for Oracle Real Application Clusters Has Been Improved Both Global and Local Transactions Are Possible The xa_open String Has Been Modied
20-33
on page 20-9
The XA Library Can Be Used with the Oracle Real Application Clusters Option on All Platforms
It was not possible with Version 7 to use the Oracle XA library together with the Oracle Real Application Clusters option on certain platforms. (Only if the platforms implementation of the distributed lock manager supported transaction-based rather than process-based locking would the two work together.) This limitation is no longer the case; if you can run the Oracle Real Application Clusters option, then you can run the Oracle XA library.
Transaction Recovery for Oracle Real Application Clusters Has Been Improved
All transactions can be recovered from any instance of Oracle Real Application Clusters. Use the xa_recover call to provide a snapshot of the pending transactions.
CONNECT scott/tiger; UPDATE Emp_tab SET Sal = Sal + 1; /* begin local transaction*/ COMMIT; /* commit local transaction*/
Global transactions, on the other hand, are coordinated by an external transaction manager such as a transaction processing monitor. In these transactions, Oracle acts as a subordinate and processes the XA commands issued by the transaction manager. The update shown below belongs to a global transaction.
xa_open(oracle_xa+acc=p/SCOTT/TIGER+sestm=10", 1, TMNOFLAGS); /* Transaction manager opens */ /* connection to the Oracle server*/ tpbegin(); /* begin global transaction, the transaction*/ /* manager issues XA commands to the oracle*/ /* server to start a global transaction */ UPDATE Emp_tab SET Sal = Sal + 1; /* Update is performed in the */ /* global transaction*/ tpcommit(); /* commit global transaction, */ /* the transaction manager issues XA commands*/ /* to the Oracle server to commit */ /* the global transaction */
The Oracle7 server forbids a local transaction from being started in an XA connection. The update shown below would return an ORA-2041 error code.
xa_open("oracle_xa+acc=p/SCOTT/TIGER+sestm=10" , 1, TMNOFLAGS); /* Transaction manager opens */ /*connection to the Oracle server */ UPDATE Emp_tab SET Sal = Sal + 1; /* Oracle 7 returns an error */
Oracle8 and later servers allow local transactions to be started in an XA connection. The only restriction is that the local transaction must be committed or rolled back before starting a global transaction in the connection.
Loose_Coupling This parameter has a Boolean value and should be set to false when connected to an Oracle7 Server. If set to true, then global transaction branches are loosely coupled; in other words, locks are not shared between branches.
SesWt
20-35
This parameters value indicates the time-out limit when waiting for a transaction branch that is being used by another session. If Oracle cannot switch to the transaction branch within SesWt seconds, then XA_RETRY is returned. Two parameters have been made obsolete and should only be used when connected to an Oracle Server Release 7.3.
s
GPWD The group password is not used by Oracle8 or later. A session that is logged in with the same user name as the session that created a transaction branch is allowed to switch to the transaction branch.
SesCacheSz This parameter is not used by Oracle8 or later because session caching has been eliminated.
Index
Symbols
%ROWTYPE attribute, 9-7 used in stored functions, 9-9 %TYPE attribute, 9-7 DROP CONSTRAINT clause, 4-26 ENABLE ALL TRIGGERS clause, 15-30 ENABLE CONSTRAINT clause, 4-22 INITRANS parameter, 7-24 ALTER TRIGGER statement DISABLE clause, 15-30 ENABLE clause, 15-29 American National Standards Institute (ANSI) ANSI-compatible locking, 7-16 anonymous PL/SQL blocks, 11-18 about, 9-2 compared to triggers, 9-21 ANSI SQL92 FIPS flagger, 7-2 AnyData datatype, 3-41 AnyDataSet datatype, 3-41 AnyType datatype, 3-41 application context as secure data cache, 12-8 bind variables, 12-9 creating, 12-16 examples, 12-17 fine-grained access control, 11-9, 12-8 how to use, 12-13 introduction, 11-4, 12-2 parallel query, 12-15 performance, 12-20 returning predicate, 12-9 security features, 12-2 setting, 12-16 USERENV namespace, 12-3 using in policy, 12-17 versioning, 12-16 application roles, 11-14
A
Active Data Object translating to PSP, 18-15 Active Server Pages translating to PSP, 18-15 ADD_CONTEXT procedure, 12-50 ADD_GROUPED_POLICY procedure, 12-50 ADD_POLICY procedure, 12-50 AFTER SUSPEND event handling suspended storage allocation, 7-40 AFTER triggers auditing and, 15-34, 15-37 correlation names and, 15-16 specifying, 15-6 ALL_ERRORS view debugging stored procedures, 9-36 ALL_SOURCE view, 9-36 ALTER privilege, 11-24 ALTER SEQUENCE statement, 2-24 ALTER SESSION SET SCHEMA statement, 12-6 ALTER SESSION statement SERIALIZABLE clause, 7-24 SET SCHEMA, 11-20 ALTER TABLE statement defining integrity constraints, 4-19 DISABLE ALL TRIGGERS clause, 15-30 DISABLE CONSTRAINT clause, 4-23
Index-1
application security considerations for use, 11-11 introduction, 11-4, 11-10 limitations, 12-60 specifying attributes, 12-3 through validation, 12-3 applications administrator, 11-13 calling stored procedures and packages, 9-45 database users, 11-11 One Big Application User model, 11-11, 11-12 roles, 11-10, 11-17 security, 11-12, 12-58 unhandled exceptions in, 9-39 AS OF clause of SELECT statement, 7-45 attributes, USERENV, 12-5 auditing compromised by One Big Application User, 11-11 n-tier systems, 13-10 triggers and, 15-33 authentication compromised by One Big Application User, 11-11 n-tier systems, 13-6 AUTHENTICATION_DATA attribute, 12-6 AUTHENTICATION_TYPE attribute, 12-6 automatic segment-space management, 3-30 autonomous routine, 7-31 autonomous scope versus autonomous transaction, 7-31 autonomous transactions, 7-31 to 7-39 AUTONOMOUS_TRANSACTION pragma, 7-31
blank padding data performance considerations, 3-13 BLOB (binary large object) datatype, 3-5, 3-8 Boolean expressions, 3-41 bulk binds, 9-18 DML statements, 9-19 FOR loops, 9-20 SELECT statements, 9-20 usage, 9-19 BY REF phrase, 10-30 BYTE qualifier for column lengths, 3-11
C
CACHE option CREATE SEQUENCE statement, 2-27 caches sequence numbers, 2-23, 2-27 call specifications, 10-4 to 10-52 callbacks, 10-47 to 10-48 canceling a cursor, 7-10 CASCADE CONSTRAINTS option, 11-35 CATPROC.SQL script, 16-2 CC datetime format element, 3-21 century, 3-20 date format masks, 3-16 CGI variables, 18-13 CHAR datatype, 3-10 column length, 3-11 CHAR qualifier for column lengths, 3-11 character data representing, 3-10 CHARSETFORM property, 10-26 CHARSETID property, 10-26 CHARTOROWID function, 3-38 CHECK constraint triggers and, 15-39, 15-45 check constraints how to use, 4-16 to 4-22 client events, 16-9 CLIENT_INFO attribute, USERENV, 12-5 CLOB datatype, 3-10 columns accessing in triggers, 15-16 default values, 4-5
B
BEFORE triggers complex security authorizations, correlation names and, 15-16 derived column values, 15-47 specifying, 15-6 BFILEs, 3-5, 3-8 binary data RAW and LONG RAW, 3-32 bind variables, 12-9 15-46
Index-2
generating derived values with triggers, 15-47 listing in an UPDATE trigger, 15-6, 15-19 multiple foreign key constraints, 4-12 number of CHECK constraints limit, 4-17 specifying length in bytes or characters, 3-11 columns, privileges, 11-32, 11-34 COMMIT statement, 7-5 comparison operators blank padding data, 3-13 comparing dates, 3-16 compile-time errors, 9-34 compiling PL/SQL procedures to native code, 9-22 composite keys restricting nulls in, 4-18 concurrency, 7-20 conditional predicates trigger bodies, 15-13, 15-18 connection pooling, 1-24 consistency read-only transactions, 7-8 constraining tables, 15-23 constraints restriction on stored functions, 9-51 See integrity constraints, 4-1 context switches reducing with bulk binds, 9-18 conversion functions, 3-38 TO_CHAR function year and century considerations, 3-20 TO_DATE function, 3-20 converting data, 3-38 ANSI datatypes, 3-37 assignments, 3-38 expression evaluation, 3-40 SQL/DS and DB2 datatypes, 3-37 cookies, 18-13 CORBA, 1-20 correlation names, 15-13 to 15-18 NEW, 15-16 OLD, 15-16 REFERENCING option and, 15-18 when preceded by a colon, 15-16 CREATE CONTEXT statement, 12-16 CREATE INDEX statement, 5-7 CREATE PACKAGE BODY statement, 9-15
CREATE PACKAGE statement, 9-15 CREATE ROLE statement, 11-25 CREATE SCHEMA statement, 2-30, 11-20 privileges required, 2-31 CREATE SEQUENCE statement CACHE option, 2-23, 2-27 examples, 2-27 NOCACHE option, 2-28 CREATE SESSION statement, 11-20 CREATE TABLE statement, 2-3 defining integrity constraints, 4-18 INITRANS parameter in, 7-24 CREATE TRIGGER statement, 15-2 REFERENCING option, 15-18 CREATE VIEW statement, 2-9 OR REPLACE option, 2-12 WITH CHECK OPTION, 2-9, 2-13 CREATE_POLICY_GROUP procedure, 12-50 creating indexes, 5-7 integrity constraints, 4-2 multiple objects, 2-30 packages, 9-15 sequences, 2-27, 2-28 synonyms, 2-29 tables, 2-3 triggers, 15-2, 15-21 views, 2-9 CURRENT_SCHEMA attribute, USERENV, 12-6 CURRENT_USER attribute, USERENV, 12-5 CURRVAL pseudo-column, 2-25 restrictions, 2-26 cursors, 7-9 canceling, 7-10 closing, 7-10 declaring and opening cursor variables, 9-32 maximum number of, 7-9 pointers to, 9-31 private SQL areas and, 7-9 shared, 12-9
D
data blocks shown in ROWIDs, 3-34
Index-3
data control in OO4O, 1-39 data conversion, 3-38 ANSI datatypes, 3-37 assignments, 3-38 expression evaluation, 3-40 SQL/DS and DB2 datatypes, 3-37 data dictionary compile-time errors, 9-36 integrity constraints in, 4-29 procedure source code, 9-36 schema object views, 2-34 data encryption, 11-5 data object number extended ROWID, 3-33, 3-34 database application administrator, 11-13 applications and security, 11-10 event notification, 16-1, 17-5 global name in a distributed system, 2-31 security and schemas, 11-20 user and application user, 11-11 datafiles shown in ROWIDs, 3-34 datatypes, 3-2 ANSI/ISO, 3-37 BFILE, 3-3 BLOB, 3-3 CHAR, 3-2, 3-10 choosing a character datatype, 3-11 CLOB, 3-2 column lengths for character types, 3-11 data conversion, 3-38 DATE, 3-2, 3-20 DB2, 3-37 INTERVAL DAY TO SECOND, 3-2 INTERVAL YEAR TO MONTH, 3-2 LONG, 3-2 LONG RAW, 3-3 MDSYS.SDO_GEOMETRY, 3-27 NCHAR, 3-2, 3-10 NCLOB, 3-2 NUMBER, 3-2 NVARCHAR2, 3-2, 3-10 RAW, 3-3 ROWID, 3-3, 3-33
SQL/DS, 3-37 summary of datatypes, 3-3 TIMESTAMP, 3-2 TIMESTAMP WITH LOCAL TIME ZONE, 3-3 TIMESTAMP WITH TIME ZONE, 3-3 VARCHAR, 3-10 VARCHAR2, 3-2, 3-10 date and time data representing, 3-14 date arithmetic, 3-40 functions for, 3-17 DATE datatype, 3-14 centuries, 3-20 data conversion, 3-38 DB_DOMAIN attribute, USERENV, 12-6 DB2 datatypes, 3-37 DBA_ERRORS view debugging stored procedures, 9-36 DBA_ROLE_PRIVS view, 11-14 DBA_SOURCE view, 9-36 DBMS_FLASHBACK package using in applications, 7-45 DBMS_LOCK package, 7-18 DBMS_OBFUSCATION_TOOLKIT, 14-1, 14-6 DBMS_RESUMABLE package handling suspended storage allocation, 7-40 DBMS_RLS package, 12-49 DBMS_SESSION package SET_CONTEXT procedure, 12-16 SET_ROLE procedure, 11-18 DBMS_SQL package advantages of, 8-16 client-side programs, 8-16 DESCRIBE, 8-16 differences with native dynamic SQL, 8-11 multiple row updates and deletes, 8-16 RETURNING clause, 8-16 See Also dynamic SQL SET_ROLE procedure, 11-19 DBMS_TYPES package, 3-41 DBMS_XMLGEN package, 3-44 DBMS_XMLQUERY package, 3-44 DBMS_XMLSAVE package, 3-44 DDL statements package state and, 9-17
Index-4
DEBUG_EXTPROC package, 10-50 debugging stored procedures, 9-41 triggers, 15-29 dedicated external procedure agents, 10-6 default column values, 4-5, 9-51 maximum savepoints, 7-6 parameters in stored functions, 9-53 role, 11-26 DELETE privilege, 11-24 DELETE statement column values and triggers, 15-16 data consistency, 7-11 triggers for referential integrity, 15-41, 15-42 dependencies among PL/SQL library objects, 9-22 in stored triggers, 15-27 schema objects trigger management, 15-21 the timestamp model, 9-23 DESC function, 5-9 DETERMINISTIC keyword, 9-57 dictionary_obj_owner event attribute, 16-3 dictionary_obj_owner_list event attribute, 16-3 dictionary_obj_type event attribute, 16-3 disabling integrity constraints, 4-21 roles, 11-6 triggers, 15-29, 15-30 Distinguished Name, 11-21 distributed databases referential integrity and, 4-15 remote stored procedures, 9-47, 9-48 triggers and, 15-21 distributed queries handling errors, 9-40 distributed transaction processing architecture, 20-2 DML_LOCKS parameter, 7-11 DROP INDEX statement, 5-6 DROP ROLE statement, 11-29 DROP TRIGGER statement, 15-29 DROP_CONTEXT procedure, 12-50 DROP_GROUPED_POLICY procedure, 12-50
DROP_POLICY procedure, 12-50 dropping indexes, 5-6 integrity constraints, 4-26 packages, 9-12 procedures, 9-11 roles, 11-29 sequences, 2-28 synonyms, 2-30 triggers, 15-29 views, 2-14 dynamic SQL, 12-43, 12-59 application development languages, invoker-rights, 8-7 invoking PL/SQL blocks, 8-6 optimization, 8-5 queries, 8-4 scenario, 8-8 See Also DBMS_SQL package See Also native dynamic SQL usage, 8-3 dynamic web pages, 18-13 dynamically typed data representing, 3-41
8-21
E
EJB, 1-20 e-mail sending from PL/SQL, 18-9 embedded SQL, 9-2 ENABLE_GROUPED_POLICY procedure, ENABLE_POLICY procedure, 12-50 enabling integrity constraints, 4-21 roles, 11-6 triggers, 15-29 encryption, 11-5 Enterprise JavaBeans, 1-20 enterprise user management, 11-12 enterprise users, 11-21 errors application errors raised by Oracle packages, 9-37
12-50
Index-5
creating views with errors, 2-11 remote procedures, 9-40 user-defined, 9-36, 9-38 event attribute functions, 16-2 event publication, ?? to 15-53, 16-1 triggering, 15-52 event triggers, 12-23 exception handlers in PL/SQL, 9-2 exceptions anonymous blocks, 9-3 during trigger execution, 15-19 effects on applications, 9-39 remote procedures, 9-40 unhandled, 9-39 exclusive locks LOCK TABLE statement, 7-15 EXECUTE privilege, 11-24 explicit locking manual locking, 7-11 extended ROWID format, 3-33 external procedure, 10-3 DEBUG_EXTPROC package, 10-50 debugging, 10-50 maximum number of parameters, 10-52 restrictions, 10-52 specifying datatypes, 10-17 EXTERNAL_NAME attribute, USERENV, 12-6 EXTPROC process running on different machines, 10-6 extproc process, 10-36
FIXED_DATE initialization parameter, 3-16 flashback query and AS OF clause of SELECT statement, 7-45 and DBMS_STATS package, 7-47 examples, 7-48 using, 7-43 FOR EACH ROW clause, 15-11 FORALL statement using, 9-18 foreign key constraints defining, 4-27, 4-28 enabling, 4-21, 4-29 NOT NULL constraint and, 4-11 one-to-many relationship, 4-11 one-to-n relationships, 4-11 UNIQUE key constraint and, 4-11 format masks TO_DATE function, 3-15 full-text search using Oracle9i Text, 3-27 functions See Also PL/SQL
G
geographic coordinate data representing, 3-27 GRANT ANY OBJECT PRIVILEGE, GRANT OPTION, 11-33 GRANT statement ADMIN OPTION, 11-30 effective time, 11-38 last DDL time, 11-36 object privileges, 11-22, 11-32 system privileges, 11-30 grantee event attribute, 16-3 granting roles, 11-30 system privileges, 11-30, 11-31 11-33
F
features, new, xxix fine grained access control, 11-4 fine-grained access control application context, 11-9, 12-8 features, 12-40 introduction, 12-40 performance, 12-43 fine-grained auditing introduction, 11-4 FIPS flagger interactive SQL statements and,
H
HEXTORAW function, 3-38 hiding PL/SQL code, 9-21 hostname, 18-10
7-2
Index-6
HTML displaying within PSP files, 18-16 retrieving from PL/SQL, 18-10 HTP and HTF packages, 18-13 HTTP URLs, 18-10
I
IBM datatypes, 3-37 image maps, 18-13 IN OUT parameter mode, 9-6 IN parameter mode, 9-6 INDEX privilege, 11-24 indexes creating, 5-7 dropping, 5-6 function-based, 5-8 guidelines, 5-3 order of columns, 5-4 privileges, 5-6 SQL*Loader and, 5-3 temporary segments and, 5-2 when to create, 5-2 index-organized tables, 6-1 to 6-20 INDICATOR property, 10-25 initialization parameters DML_LOCKS, 7-11 OPEN_CURSORS, 7-9 REMOTE_DEPENDENCIES_MODE, 9-29 ROW_LOCKING, 7-11 SERIALIZABLE, 7-11 INITRANS parameter, 7-24 INSERT privilege, 11-24 INSERT statement column values and triggers, 15-16 read consistency, 7-11 instance_num event attribute, 16-3 INSTEAD OF triggers, 15-7 on nested table view columns, 15-17 integrity constraints CHECK, 4-16 to ?? composite UNIQUE keys, 4-7 defining, 4-18 disabling, 4-20, 4-22, 4-23 dropping, 4-26
enabling when violations exist, 4-21 examples, 4-2 exceptions to, 4-24 listing definitions of, 4-29 naming, 4-20 NOT NULL, 4-3 performance considerations, 4-3 PRIMARY KEY, 4-6 privileges required for creating, 4-19 renaming, 4-25 triggers vs., 15-2, 15-38 UNIQUE, 4-7 violations, 4-21 when to use, 4-2 interactive block execution, 9-44 INTERVAL DAY TO SECOND datatype, 3-14 INTERVAL YEAR TO MONTH datatype, 3-14 invalid views, 2-14 invokers rights stored procedures, 11-18 invoker-rights dynamic SQL, 8-7 is_alter_column event attribute, 16-3 ISDBA attribute, USERENV, 12-5 ISOLATION LEVEL changing, 7-24 SERIALIZABLE, 7-24
J
J2EE, 1-20 JAAS, 1-20 Java calling methods through call specifications, generating wrapper classes with JPublisher, 1-16 in the RDBMS, 1-8 loading into the database, 10-5 overview of JDBC, 1-9 overview of SQLJ, 1-14 vs PL/SQL, 1-42 Javascript translating to PSP, 18-15 JavaServer Pages translating to PSP, 18-15 JDBC
10-4
Index-7
See Oracle JDBC, 1-9 join views, 2-15 DELETE statements, 2-18 key-preserved tables in, 2-16 mergeable, 2-9, 2-16 modifying, 2-17 UPDATE statements, 2-18 when modifiable, 2-15 JPublisher, 1-18 JScript translating to PSP, 18-15 JSPs, 1-20
user locks, 7-18 UTLLOCKT.SQL script, 7-20 login triggers, 12-13, 12-16, 12-17 LONG columns restrictions on, 3-30 where referenced from, 3-29 LONG datatype, 3-10 in triggers, 3-31 switching to LOB datatypes, 3-28 use in triggers, 15-21 LONG RAW datatype, 3-32 LOWER function, 5-9
K
key-preserved tables in join views, 2-16 in outer joins, 2-21 keys foreign keys, 4-27 unique composite, 4-7
M
mail sending from PL/SQL, 18-9 manual locking, 7-11 LOCK TABLE statement, 7-12 MAX_ENABLED_ROLES parameter, 11-26, 11-29 MDSYS.SDO_GEOMETRY datatype, 3-27 memory scalability, 9-64 middle tier systems, 12-4 migration ROWID format, 3-35 modes of parameters, 9-6 modifiable join view definition of, 2-15 mutating tables, 15-23
L
large datatypes representing with LOBs, 3-27 libraries, 1-41 library units remote dependencies, 9-22 Lightweight Directory Access Protocol (LDAP), 12-20 lightweight sessions, 13-6 loadjava utility, 1-20 loadpsp command, 18-23 LOB datatype support in OO4O, 1-37 use in triggers, 15-17 LOCK TABLE statement, 7-12 locking manual (explicit), 7-11 locks distributed, 7-11 LOCK TABLE statement, 7-12, 7-13 privileges for manual acquirement, 7-15
N
name resolution, 2-32 native dynamic SQL advantages of, 8-12 differences with DBMS_SQL package, fetching into records, 8-15 performance, 8-14 See Also dynamic SQL user-defined types, 8-15 native execution of PL/SQL procedures, 9-22 NCHAR datatype, 3-2, 3-10
8-11
Index-8
NCLOB datatype, 3-10 NEW correlation name, 15-16 new features, xxix NEXTVAL pseudo-column, 2-25 restrictions, 2-26 NLS_DATE_FORMAT parameter, 3-15 NLSSORT order, and indexes, 5-9 NOCACHE option CREATE SEQUENCE statement, 2-28 NOT NULL constraint CHECK constraint and, 4-18 data integrity, 4-21 when to use, 4-3 NOWAIT option, 7-12 NUMBER datatype, 3-13 numeric data representing, 3-13 NVARCHAR2 datatype, 3-2, 3-10
O
OAS, 18-13 object columns, indexes on, 5-9 object support in OO4O, 1-37 objects GRANT OPTION, 11-33 granting privileges, 11-23, 11-32 privileges, 11-22 revoking privileges, 11-34 objects, schema listing information, 2-34 name resolution, 2-32 renaming, 2-33 OC4J, 1-20 OCCI overview, 1-26 OCI, 9-2 applications, 9-4 cancelling cursors, 7-10 closing cursors, 7-10 enabling roles, 11-7 overview, 1-26 parts of, 1-28 vs precompilers, 1-40 OLD correlation name, 15-16
one-to-many relationship with foreign keys, 4-11 one-to-one relationship with foreign keys, 4-11 OO4O See Oracle Objects for OLE, 1-32 open string for XA, 20-10 OPEN_CURSORS parameter, 7-9 operating system roles, 11-29 OR REPLACE clause for creating packages, 9-16 ora_dictionary_obj_owner event attribute, 16-3 ora_dictionary_obj_owner_list event attribute, 16-3 ora_dictionary_obj_type event attribute, 16-3 ora_grantee event attribute, 16-3 ora_instance_num event attribute, 16-3 ora_is_alter_column event attribute, 16-3 ora_is_creating_nested_table event attribute, 16-4 ora_is_drop_column event attribute, 16-4 ora_is_servererror event attribute, 16-4 ora_login_user event attribute, 16-4 ora_privileges event attribute, 16-4 ora_revokee event attribute, 16-4 ora_server_error event attribute, 16-4 ora_sysevent event attribute, 16-4 ora_with_grant_option event attribute, 16-7 ORA-21301 error, fixing, 20-15 OraAQ object, 1-36 OraAQAgent object, 1-37 OraAQMsg object, 1-37 OraBFILE object, 1-38 OraBLOB object, 1-38 Oracle Advanced Security, 11-21 Oracle Application Server (OAS), 18-13 Oracle Call Interface See OCI Oracle Data Control (ODC), 1-39 Oracle errors, 9-3 Oracle Internet Directory, 13-5 Oracle JDBC definition, 1-9 example, 1-12 OCI driver, 1-10 Oracle extensions, 1-11
Index-9
server driver, 1-11 stored procedures, 1-9 thin driver, 1-10 Oracle Objects for OLE automation server, 1-32 C++ Class Library, 1-39 data control, 1-39 LOB and object support, 1-37 object model, 1-32 overview, 1-31 Oracle SQLJ advantages over JDBC, 1-15 definition, 1-14 design, 1-15 example, 1-17 in the server, 1-20 stored programs, 1-20 Oracle supplied packages, 9-17 OraCLOB object, 1-38 OraDatabase object, 1-34 OraDynaset object, 1-34 OraField object, 1-35 OraMeta Data object, 1-35 OraParamArray object, 1-36 OraParameter object, 1-35 OraServer object, 1-33 OraSession object, 1-33 OraSQLStmt object, 1-36 OS_ROLES parameter, 11-29 OS_USER attribute, USERENV, 12-6 OUT parameter mode, 9-6 outer joins, 2-20 key-preserved tables in, 2-21 overloading of packaged functions, 9-63 stored procedure names, 9-13 using RESTRICT_REFERENCES, 9-63 OWA* packages, 18-13
P
package body, 9-13 package specification, packages, 1-41 creating, 9-15 9-13
DBMS_OUTPUT example of use, 9-3 DEBUG_EXTPROC, 10-50 dropping, 9-12 in PL/SQL, 9-13 naming of, 9-16 privileges for execution, 9-46 privileges required to create, 9-16 privileges required to create procedures in, 9-10 serially reusable packages, 9-64 session state and, 9-17 synonyms, 9-50 where documented, 9-17 parallel execution servers, 12-15 parallel query, and SYS_CONTEXT, 12-15 parallel server distributed locks, 7-11 sequence numbers and, 2-24 PARALLEL_ENABLE keyword, 9-57 parameters default values, 9-9 with stored functions, 9-53 modes, 9-6 parse tree, 15-27 Pascal Calling Standard, 10-10 passwords role, 11-8, 11-27 pcode when generated for triggers, 15-27 performance index column order, 5-4 native dynamic SQL, 8-14 PL, 8-7 PL/SQL, 9-2 advantages, 1-4 anonymous blocks, 9-2, 11-18 calling remote stored procedures, 9-48 cursor variables, 9-31 dependencies among library units, 9-22 dynamically modifying SQL statements, 12-59 exception handlers, 9-2 features, 1-4 functions arguments, 9-53 overloading, 9-63
Index-10
parameter default values, 9-53 purity level, 9-63 RESTRICT_REFERENCES pragma, 9-60 using, 9-50 hiding source code, 9-21 invoking with dynamic SQL, 8-6 objects, 1-6 packages, 9-13 program units, 9-2 replaced views and, 2-12 RAISE statement, 9-38 sample code, 1-4 serially reusable packages, 9-64 server pages, 18-13 to 18-24 setting context, 12-13 tables, 9-9 of records, 9-9 trigger bodies, 15-13, 15-16 user-defined errors, 9-37 vs Java, 1-42 web toolkit, 18-13 wrapper to hide code, 9-21 PLSQL_COMPILER_FLAGS initialization parameter, 9-22 pragma, 7-31, 7-39 RESTRICT_REFERENCES pragma, 9-60 SERIALLY_REUSABLE pragma, 9-64, 9-65 precompilers, 9-45 applications, 9-4 calling stored procedures and packages, 9-45 vs OCI, 1-40 PRIMARY KEY constraints choosing a primary key, 4-6 disabling, 4-22 enabling, 4-21 multiple columns in, 4-6 UNIQUE key constraint vs., 4-7 private SQL areas cursors and, 7-9 privileges altering sequences, 2-24 creating integrity constraints, 4-19 creating triggers, 15-26 dropping a view, 2-14 dropping sequences, 2-28
dropping triggers, 15-29 encapsulating in stored procedures, 11-7 granting, 11-30, 11-32 granting to PUBLIC, 11-37 index creation, 5-6 managing, 11-13, 11-22 manually acquiring locks, 7-15 middle tier, 13-7 object, 11-23 on selected columns, 11-34 recompiling triggers, 15-28 renaming objects, 2-34 replacing views, 2-12 revoking, 11-34 sequence creation, 2-24 SQL statements permitted, 11-23 stored procedure execution, 9-46 synonym creation, 2-29 triggers, 15-26 using a view, 2-14 using sequences, 2-28 view creation, 2-11 Pro*C/C++ overview of application development, 1-21 to ?? Pro*COBOL overview of application development, 1-24 to ?? procedures called by triggers, 15-21 external, 10-3 PRODUCT_USER_PROFILE table, 11-7, 12-58 program units in PL/SQL, 9-2 property CHARSETFORM, 10-26 CHARSETID, 10-26 INDICATOR, 10-25 proxy authentication, 11-5 PROXY_USER attribute, 12-4, 12-6 pseudocolumns modifying views, 15-8 PSP See PL/SQL server pages .psp files, 18-15 PUBLIC user group, 11-37 publish-subscribe, 17-2 to 17-6 purity level, 9-55
Index-11
Q
queries capturing as views, 2-9 dynamic, 8-4 errors in distributed queries, 9-40 reconstructing data at a point in time, 7-43 speeding up with temporary tables, 2-4
R
RAISE statement, 9-38 RAISE_APPLICATION_ERROR procedure, 9-36 remote procedures, 9-40 raising exceptions triggers, 15-19 RAW datatype, 3-32 RAWTOHEX function, 3-38 RAWTONHEX function, 3-38 read-only transactions, 7-8 reauthenticating clients, 13-5, 13-8 records in SQL INSERT and UPDATE statements, 8-21 REF column indexes on, 5-9 REFERENCES privilege, 11-24, 11-35 REFERENCING option, 15-18 referential integrity distributed databases and, 4-15 one-to-many relationship, 4-11 one-to-one relationship, 4-11 privileges required to create foreign keys, 4-27 self-referential constraints, 15-42 triggers and, 15-39 to 15-43 REFRESH_GROUPED_POLICY procedure, 12-50, 12-51 REFRESH_POLICY procedure, 12-50, 12-51 remote dependencies, 9-22 signatures, 9-24 specifying timestamps or signatures, 9-29 remote exception handling, 9-40, 15-19 REMOTE_DEPENDENCIES_MODE parameter, 9-29 RENAME statement, 2-33 reparsing, 12-16
repeatable reads, 7-8, 7-11 resource manager, 20-2 events, 16-8 RESOURCE privilege, 11-20 RESTRICT_REFERENCES pragma syntax for, 9-60 using to control side effects, 9-60 restrictions system triggers, 15-25 resumable storage allocation, 7-40 examples, 7-41 reusable packages, 9-64 REVOKE statement, 11-38 revoking privileges on selected columns, 11-34 roles and privileges, 11-31 RM (resource manager), 20-2 RNDS argument, 9-60 RNPS argument, 9-60 ROLE_SYS_PRIVS view, 11-14 ROLE_TAB_PRIVS view, 11-14 roles ADMIN OPTION, 11-31 advantages, 11-14 application, 11-17, 11-22, 12-58 central management, 11-24 creating, 11-24 default, 11-26 dropping, 11-29 enabling, 11-17 enabling and disabling, 11-6 GRANT and REVOKE statements, 11-29 granting, 11-30 granting to PUBLIC, 11-37 managing, 11-22 operating system, 11-29 passwords, 11-8, 11-27 protecting, 11-24 recommended practices, 11-6 restricting from tool users, 12-58 revoking, 11-31 secure application, 11-4 SET ROLE statement, 11-29 system privileges, 11-30 usefulness compromised, 11-12
Index-12
user, 11-17, 11-22 WITH GRANT OPTION, 11-33 ROLLBACK statement, 7-6 rolling back transactions to savepoints, 7-6 routines autonomous, 7-31 external, 10-3 service, 10-37 row locking manually locking, 7-17 row triggers defining, 15-11 REFERENCING option, 15-18 timing, 15-6 UPDATE statements and, 15-6, 15-19 ROW_LOCKING parameter, 7-11 ROWID datatype, 3-33 extended ROWID format, 3-33 migration, 3-35 ROWIDTOCHAR function, 3-38 ROWIDTONCHAR function, 3-38 rows format, 2-2 header, 2-2 shown in ROWIDs, 3-34 size, 2-2 violating integrity constraints, 4-21 ROWTYPE_MISMATCH exception, 9-34 RR date format, 3-20 RS locks LOCK TABLE statement, 7-13 run-time error handling, 9-36 RX locks LOCK TABLE statement, 7-13
S
S locks LOCK TABLE statement, 7-13 SAVEPOINT statement, 7-6 savepoints maximum number of, 7-6 rolling back to, 7-6 scalability
serially reusable packages, 9-64 schema-independent users, 11-21, 11-22 schemas default, 12-6 unique, 11-20 scope, autonomous, 7-31 scripting, 18-13 scrollable cursors, 1-24 search data representing, 3-27 secure application, xxxv, 11-14 Secure Sockets Layer (SSL) protocol, 13-5 security application context, 12-2 enforcement in application, 11-12 enforcement in database, 11-12 features of Oracle8i, 11-4 fine-grained access control, 12-40 policies administering, 12-49 applied within database, 12-60 centrally managed, 12-59 example, 12-43 implementing, 12-8 multiple policies per table, 12-42 on tables or views, 12-40 technical issues, 11-3 policy for applications, 11-10, 12-58 roles, advantages, 11-14 table- or view-based, 12-40 threats and countermeasures, 11-2 SELECT privilege, 11-24 SELECT statement read consistency, 7-11 SELECT ... FOR UPDATE, 7-17 SEQUENCE_CACHE_ENTRIES parameter, sequences accessing, 2-24 altering, 2-24 caching numbers, 2-23 caching sequence numbers, 2-27 creating, 2-23, 2-27, 2-28 CURRVAL, 2-24, 2-26 dropping, 2-28 initialization parameters, 2-23
2-27
Index-13
NEXTVAL, 2-25 parallel server, 2-24 privileges needed, 2-24 to 2-28 reducing serialization, 2-25 SERIALIZABLE option for ISOLATION LEVEL, 7-24 SERIALIZABLE parameter, 7-11 serializable transactions, 7-20 serially reusable PL/SQL packages, 9-64 SERIALLY_REUSABLE pragma, 9-65 service routine, 10-37 examples, 10-37 servlets, 1-20 session primitives, 12-3 SESSION_USER attribute, USERENV, 12-5 sessions package state and, 9-17 SET ROLE statement ALL EXCEPT option, 11-28 ALL option, 11-28 associating privileges with role, 11-17 at startup, 11-6 disabling, 11-7 enabling roles, 11-27 equivalent to SET_ROLE, 11-18 operating system roles, 11-29 protecting role use, 11-25 role passwords, 11-8 SET TRANSACTION statement, 7-8 ISOLATION LEVEL clause, 7-24 SERIALIZABLE, 7-24 SET_CONTEXT procedure, 12-16 SET_ROLE procedure, 11-18 SGA See Also system global area share locks (S) LOCK TABLE statement, 7-13 share row exclusive locks (SRX) LOCK TABLE statement, 7-14 side effects, 9-6, 9-55 signatures PL/SQL library unit dependencies, 9-22 to manage remote dependencies, 9-24 SOAP, 1-20 SORT_AREA_SIZE parameter
index creation and, 5-2 sorting with function-based indexes, 5-8 SQL statements dynamic, 12-14 execution, 7-2 in trigger bodies, 15-16, 15-21 not allowed in triggers, 15-21 privileges required for, 11-23 restricting ad hoc use, 12-57 SQL*Loader indexes and, 5-3 SQL*Module applications, 9-4 SQL*Plus anonymous blocks, 9-4 compile-time errors, 9-34 invoking stored procedures, 9-43 loading a procedure, 9-10 restricting ad hoc use, 12-57 SET SERVEROUTPUT ON command, 9-3 SHOW ERRORS command, 9-35 SQL/DS datatypes, 3-37 SQLStmt object, 1-36 SRX locks LOCK Table statement, 7-14 standards ANSI, 7-16 state session, of package objects, 9-17 statement triggers conditional code for statements, 15-18 row evaluation order, 15-22 specifying SQL statement, 15-5 timing, 15-6 trigger evaluation order, 15-22 UPDATE statements and, 15-6, 15-19 valid SQL statements, 15-21 storage allocation errors resuming execution after, 7-40 stored functions, 9-5 creating, 9-9 stored procedures, 9-5 argument values, 9-46 creating, 9-9
Index-14
distributed query creation, 9-40 encapsulating privileges, 11-7 exceptions, 9-36, 9-38 invokers rights, 11-18 invoking, 9-43 names of, 9-5 overloading names of, 9-13 parameter default values, 9-9 privileges, 9-46 remote, 9-47 remote objects and, 9-48 storing, 9-9 synonyms, 9-50 turning into a web page, 18-13 synonyms, 2-29 stored procedures and packages, 9-50 SYS schema, 12-16 SYS_CONTEXT function access control, 12-22 dynamic SQL statements, 12-14 parallel query, 12-15 storing session variables, 12-16 syntax, 12-14 USERENV namespace, 12-4 SYS_XMLAGG function, 3-44 SYS_XMLGEN function, 3-44 SYSDATE function, 3-16 system events, 16-1 attributes, 16-2 client events, 16-9 resource manager events, 16-8 tracking, 15-50, 16-1 system global area holds sequence number cache, 2-27 system privileges, 11-30, 11-31 system-specific Oracle documentation PL/SQL wrapper, 9-22
T
table- or view-based security, tables constraining, 15-23 creating, 2-3 12-40
designing, 2-3 guidelines, 2-2, 2-3 in PL/SQL, 9-9 index-organized, 6-1 to 6-20 key-preserved, 2-16 mutating, 15-23 tablespaces automatic segment-space management, 3-30 TCP/IP, 18-10 temporary segments index creation and, 5-2 TERMINAL attribute, USERENV, 12-5 text search using Oracle9i Text, 3-27 The DBMS_OBFUSCATION_TOOLKIT Package, 14-2 third generation language, 9-2 time and date data representing, 3-14 time zones functions for, 3-18 TIMESTAMP datatype, 3-14 TIMESTAMP WITH LOCAL TIME ZONE datatype, 3-14 TIMESTAMP WITH TIME ZONE datatype, 3-14 timestamps PL/SQL library unit dependencies, 9-22 TM (transaction manager), 20-2 TO_CHAR function, 3-38 CC date format, 3-21 RR date format, 3-12 TO_CLOB function, 3-38 TO_DATE function, 3-15, 3-38 RR date format, 3-20 TO_NCHAR function, 3-38 TO_NCLOB function, 3-38 TO_NUMBER function, 3-38 transaction manager, 20-2 transactions autonomous, 7-31 to 7-39 manual locking, 7-11 read-only, 7-8 serializable, 7-20 SET TRANSACTION statement, 7-8 triggers
Index-15
about, 9-21 accessing column values, 15-16 AFTER, 15-6, 15-16, 15-34, 15-37 auditing with, 15-33, 15-34 BEFORE, 15-6, 15-16, 15-46, 15-47 body, 15-13, 15-18, 15-19, 15-21 check constraints, 15-45, 15-46 client events, 16-9 column list in UPDATE, 15-6, 15-19 compiled, 15-27 conditional predicates, 15-13, 15-18 CREATE TRIGGER ON, 11-24 creating, 15-2, 15-21, 15-26 data access restrictions, 15-46 debugging, 15-29 designing, 15-2 disabling, 15-29, 15-30 distributed query creation, 9-40 enabling, 15-29 error conditions and exceptions, 15-19 event, 12-23 events, 15-5 examples, 15-32 to 15-48 FOR EACH ROW clause, 15-11 generating derived column values, 15-47 illegal SQL statements, 15-21 INSTEAD OF triggers, 15-7 integrity constraints vs., 15-2, 15-38 listing information about, 15-30 login, 12-13, 12-16, 12-17 migration issues, 15-28 modifying, 15-29 multiple same type, 15-22 mutating tables and, 15-23 naming, 15-5 package variables and, 15-22 privileges, 15-26 to drop, 15-29 procedures and, 15-21 recompiling, 15-28 REFERENCING option, 15-18 referential integrity and, 15-39 to 15-43 remote dependencies and, 15-21 remote exceptions, 15-19 resource manager events, 16-8
restrictions, 15-12, 15-21 row, 15-11 row evaluation order, 15-22 scan order, 15-22 stored, 15-27 system triggers, 15-4 on DATABASE, 15-4 on SCHEMA, 15-4 trigger evaluation order, 15-22 use of LONG and LONG RAW datatypes, username reported in, 15-26 WHEN clause, 15-12 TRUNC function, 3-16 TRUST keyword, 9-62 tuning using LONGs, 3-31
15-21
U
UDDI, 1-20 unhandled exceptions, 9-39 UNIQUE key constraints combining with NOT NULL constraint, 4-5 composite keys and nulls, 4-7 disabling, 4-22 enabling, 4-21 PRIMARY KEY constraint vs., 4-7 when to use, 4-7 UPDATE statement column values and triggers, 15-16 data consistency, 7-11 triggers and, 15-6, 15-19 triggers for referential integrity, 15-41, 15-42 UPPER function, 5-9 URLs, 18-10 USER function, 4-5 user locks requesting, 7-18 USER_ERRORS view debugging stored procedures, 9-36 USER_SOURCE view, 9-36 user-defined errors, 9-36, 9-38 USERENV function, 12-4, 13-9, 14-7 USERENV namespace, 12-3, 12-5 usernames
Index-16
as reported in a trigger, 15-26 schemas, 11-20 users dropped roles, 11-29 enabling roles for, 11-17 enterprise, 11-21 PUBLIC group, 11-37 restricting application roles, 12-58 schema-independent, 11-21 UTL_HTTP package, 18-10 UTL_INADDR package, 18-10 UTL_SMTP package, 18-9 UTL_TCP package, 18-10 UTLLOCKT.SQL script, 7-20
W
web pages dynamic, 18-13 WebDB, 18-13 WHEN clause, 15-12 cannot contain PL/SQL expressions, 15-13 correlation names, 15-16 examples, 15-2, 15-11, 15-31, 15-40 EXCEPTION examples, 15-19, 15-40, 15-45, 15-46 WHERE clause, dynamic SQL, 12-59 WITH clause, 2-7 using to simplify complex queries, 2-7 WITH CONTEXT clause, 10-31 WNDS argument, 9-60 WNPS argument, 9-60 wrapper to hide PL/SQL code, 9-21
V
validation function, 12-3 VARCHAR datatype, 3-10 VARCHAR2 datatype, 3-2, 3-10 column length, 3-11 when to use, 3-11 VBScript translating to PSP, 18-15 versioning, in application context, 12-16 views containing expressions, 15-8 creating, 2-9 creating with errors, 2-11 dropping, 2-14 FOR UPDATE clause and, 2-9 inherently modifiable, 15-7 invalid, 2-14 join views, 2-15 modifiable, 15-7 ORDER BY clause and, 2-9 privileges, 2-11 pseudocolumns, 15-8 replacing, 2-11 restrictions, 2-13 using, 2-12 when to use, 2-9 WITH CHECK OPTION, 2-9 virtual private database (VPD), 11-7, 11-12, 12-8, 12-59, 12-60
X
X locks LOCK TABLE statement, 7-15 XA library, 20-1 to 20-36 xa_open string, 20-10 XML as document type for PSP file, 18-16 searching with Oracle9i Text, 3-27 XML data representing, 3-44 X/Open distributed transaction processing architecture, 20-2
Y
year 2000, 3-20
Index-17
Index-18