Entry Topic
Oracle7 Server Application Developer's Guide

Oracle7™ Server Application Developer's Guide

PREFACE

CHAPTER 1. THE APPLICATION DEVELOPER

CHAPTER 2. MANAGING SCHEMA OBJECTS

CHAPTER 3. SELECTING A DATATYPE

CHAPTER 4. PROCESSING SQL AND PL/SQL STATEMENTS

CHAPTER 5. TUNING SQL STATEMENTS

CHAPTER 6. MAINTAINING DATA INTEGRITY

CHAPTER 7. USING PROCEDURES AND PACKAGES

CHAPTER 8. USING DATABASE TRIGGERS

CHAPTER 9. MANAGING DEPENDENCIES AMONG SCHEMA OBJECTS

CHAPTER 10. ESTABLISHING A SECURITY POLICY

CHAPTER 11. DESIGNING DISTRIBUTED APPLICATIONS

CHAPTER 12. MANAGING SNAPSHOTS

APPENDIX A. SUPPLIED PACKAGES

APPENDIX B. PERFORMANCE DIAGNOSTIC TOOLS

APPENDIX C. SQL*FORMS AND ORACLE

APPENDIX D. DATA DICTIONARY REFERENCE

APPENDIX E. NATIONAL LANGUAGE SUPPORT

APPENDIX F. OPERATING SYSTEM SPECIFIC INFORMATION


This help file created via:

 Version 1.0n

© 1994 Oracle Corporation Inc.

Authored by KM .


Part# A12716-1


Oracle7ä Server Application Developer's Guide
Oracle7™ Server Application Developer's Guide

August 10, 1993

Part No. A12716-1

Oracle7 Server Application Developer's Guides

Part No. A12716-1

Copyright  1993 Oracle Corporation

Contributing Authors:  Eric Armstrong, Steven Bobrowski, John Frazzini, Brian Linden, Maria Pratt

Contributors:  Richard Allen, Lori Asher, Andre Bakker, Cynthia Closkey, Gary Hallmark, Michael Hartstein, Kenneth Jacobs, Sandeep Jain, Robert Jenkins, Christopher Jones, Michael Kennedy, Jonathan Klein, Robert Kooi, Juan Loaiza, William Maimone, Andrew Mendelsohn, Mark Moore, Steve Muench, Sameer Patkar, Edward Peeler, Thomas Portfolio, Tuomas Pystnen, Brian Quigley, Timothy Smith, Lawrence To, Mustafa Vahanvaty, Kevin Wharton, Joyo Wijaya, Beth Winslow

This software/documentation contains proprietary information of Oracle Corporation; it is provided under a license agreement containing restrictions on use and disclosure and is also protected by copyright law.  Reverse engineering of the software is prohibited.

If this software/documentation is delivered to a U.S. Government Agency of the Department of Defense, then it is delivered with Restricted Rights and the following legend is applicable:

Restricted Rights Legend

Use, duplication, or disclosure by the Government is subject to restrictions

as set forth in subparagraph (c)(1)(ii) of DFARS 252.227-7013, Rights in

Technical Data and Computer Software (October 1988).

Oracle Corporation, 500 Oracle Parkway, Redwood City, CA  94065.

If this software/documentation is delivered to a U.S. Government Agency not within the Department of Defense, then it is delivered with "Restricted Rights," as defined in FAR 52.227-14, Rights in Data - General, including Alternate III (June 1987).

The information in this document is subject to change without notice.   If you find any problems in the documentation, please report them to us in writing.   Oracle Corporation does not warrant that this document is error-free.

ORACLE, Pro*Ada, Pro*COBOL, Pro*FORTRAN, Pro*PL/I, Pro*Pascal, SQL*DBA, SQL*Forms, SQL*Loader, SQL*Mail, SQL*Net, SQL*Plus, and SQL*ReportWriter are registered trademarks of Oracle Corporation. ORACLE7, ORACLE Parallel Server, PL/SQL, and Pro*C are trademarks of Oracle Corporation.

VMS is a registered trademark of Digitial Equipment Corporation


PREFACE

This Guide describes all features of the ORACLE7 Seerver, a relational database management system (RDBMS). This Guide is provided so that the reader can understand how to develop applications for ORACLE7.

Information in this Guide applies to the ORACLE7 Server, running on all operating systems. It provides information about the base ORACLE Server product and the special options, including:

•	procedural database option

•	distributed database option

•	Parallel Server option

Any chapter of this Guide that applies only to a particular option is clearly indicated on the first page of the chapter.

________________________________________

Audience

This Guide is written for those people who are responsible for developing applications to run with ORACLE7. These application developers are assumed to be responsible for designing, implementing, and testing database applications. Database application developers should also refer to the publication corresponding to the tool or language product they are using to develop ORACLE database applications.

Knowledge Assumed of the Reader

Readers of this Guide are assumed to be familiar with relational database concepts. They are also assumed to be familiar with the operating system environment under which they are running ORACLE.

As a prerequisite, all readers should read the first chapter of the ORACLE7 Server Concepts Manual, "A Technical Introduction to the ORACLE Server." This chapter is a comprehensive introduction to the concepts and terminology used throughout this Guide.

Readers Interested in Installation and Migration Information

This Guide is not an installation or migration manual. If your primary interest is installation, refer to the installation or user's guide for your particular operating system. If your primary interest is database or application migration, refer to the ORACLE7 Server Migration Guide.

Readers Interested in Application Design Information

In addition to application developers, experienced users of ORACLE and some database administrator's might also find information in this Guide useful. However, database administrator's should also refer to the ORACLE7 Server Administrator's Guide for information on administering the operation of an ORACLE database.

Readers Interested in Trusted ORACLE

If you are administering or developing applications for a Trusted ORACLE database, you should also refer to the Trusted ORACLE7 Server Administrator's Guide.

________________________________________

How This Guide Is Organized

This Guide is divided into 12 chapters and six appendices, as described below.

Chapter 1: The Application Developer

This chapter provides an overview of the application development process.

Chapter 2: Managing Schema Objects

This chapter describes how to manage the objects that can be created in the domain of a specific user (schema), including tables, views, numeric sequences, and synonyms. Performance enhancements of data retrieval through the use of indexes and clusters is also discussed.

Chapter 3: Selecting a Datatype

This chapter describes how to choose the correct ORACLE datatype. The datatypes described include fixed- and variable-length character strings, numeric data, dates, and binary large objects.

Chapter 4: Processing SQL and PL/SQL Statements

This chapter explains the steps that ORACLE must perform to process the various types of SQL commands and PL/SQL statements.

Chapter 5: Tuning SQL Statements

This chapter helps you write SQL statements so they are processed most efficiently by ORACLE. This chapter discusses these topics: the optimizer, indexes, clusters, hashing and hints.

Chapter 6: Maintaining Data Integrity

This chapter describes how to use declarative integrity constraints to provide data integrity within an ORACLE database.

Chapter 7: Using Procedures and Packages

This chapter describes how to create procedures that can be stored in the database for continued use. Grouping these procedures into packages is also described.

Chapter 8: Using Database Triggers

This chapter describes how to create and debug database triggers. Numerous examples are included.

Chapter 9: Managing Dependencies Among Schema Objects

This chapter describes how to manage the dependencies between related views, procedures, packages, and triggers.

Chapter 10: Establishing a Security Policy

This chapter describes how to design a security policy using ORACLE's security features.

Chapter 11: Designing Distributed Applications

This chapter describes how to design applications to run in a distributed database environment.

Chapter 12: Managing Snapshots

This chapter describes how to use table snapshots to replicate data among nodes of a distributed database.

Appendix A: Supplies Packages

This appendix describes the packages that are supplied with the procedural option of ORACLE.

Appendix B: Performance Diagnostic Tools

This appendix discusses the following tools that monitor performance: the SQL trace facility and the EXPLAIN PLAN statement.

Appendix C: SQL*Forms and ORACLE

This appendix describes the interaction between SQL*Forms and ORACLE.

Appendix D: Data Dictionary Reference

This appendix is a reference to the many data dictionary view of an ORACLE database.

Appendix E: Operating System Specific Information

This appendix is a summary of all the operating system specific references contained within this Guide.

________________________________________

How to Use This Guide

Every reader of this Guide must read Chapter 1 of the ORACLE7 Server Concepts Manual, "A Technical Introduction to the ORACLE Server." This overview of the concepts and terminology related to ORACLE provides a foundation for the more detailed information in this Guide.

Chapter 1 of this Guide, "The Application Developer," provides an overview of the application development process. The remaining chapters describe the different facilities available in ORACLE that are used to develop applications.

________________________________________

Conventions Used in This Guide

The following sections explain the conventions used in this Guide.

Text of the Guide

The following section explains the conventions used within the text of this Guide:

UPPERCASE  WORDS	Uppercase text is used to call attention to command keywords, object names, parameters, filenames, and so on. For example:

If you create a private rollback segment, the name of the rollback segment must be included in the ROLLBACK_SEGMENTS parameter of the parameter file

Italicized Words	Italicized words within text are used to indicate the first occurrence and definition of a term, as in the following example:

A database is a collection of data to be treated as a unit. The general purpose of a database is to store and retrieve related information, as needed.

Italicized words are also used to indicate book titles and to highlight names of performance statistics.

Bold Words	Bolding within text is used to call special attention to important information. For example:

In summary, remember that this procedure provides a reasonable estimate of a table's size, not an exact number of blocks or bytes.

Examples of Commands and Statements

SQL, SQL*DBA, and SQL*Plus commands and statements appear separated from the text of paragraphs in a fixed-width font:

ALTER TABLESPACE users ADD DATAFILE 'users2.ora' SIZE 50K;

Punctuation

 , ' "	Example statements may include punctuation such as commas or quotation marks. All punctuation given in example statements is required. All example statements are terminated with a semicolon. Depending on the application being used, a semi-colon or other terminator may or may not be required to end a statement.

Uppercase Words  INSERT, SIZE	Uppercase words in example statements are used to indicate the keywords within ORACLE SQL. However, note that when issuing statements, keywords are not case-sensitive.

Lowercase Words emp, users2.ora	Lowercase words in example statements are used to indicate words supplied only for the context of the example. For example, lowercase words may indicate the name of a table, column, or file. Some operating systems are case sensitive, so refer to your installation or user's guide to determine whether you must pay attention to case.

________________________________________

Your Comments Are Welcome

We value and appreciate your comments as an ORACLE user and reader of the manuals. As we write, revise, and evaluate, your opinions are the most important input we receive. At the back of this Guide is a Reader's Comment Form, which we encourage you to use to tell us what you like and dislike about this Guide or other ORACLE manuals. If the form has been used or you would like to contact us, please use the following address or FAX number, or call us at (415) 506-7000.

ORACLE7 Server Documentation Manager

 	Oracle Corporation

 	500 Oracle Parkway

 	Redwood Shores, CA  94065

FAX: (415) 506-7200


CHAPTER 1. THE APPLICATION DEVELOPER

This chapter briefly outlines the steps involved in designing and implementing an ORACLE database application. More detailed information needed to perform these tasks is provided later in this document. Although the specific tasks vary depending upon the type and complexity of the application being developed, in general the responsibilities of the application developer include:

•	designing and developing the database application

•	designing the database structure for that application

•	estimating storage requirements for the application

•	specifying modifications of the database structure for that application

•	relaying the above information to a database administrator

•	tuning of the application during development

This book is not meant to serve as a textbook on database or application design. If you are not already familiar with these areas, you should consult a text for guidance. Where appropriate, you will be directed to other sections of this document for additional information.

________________________________________

Assessing Needs

The first step in designing a usable application is determining what problem you are trying to solve. It is important that you do not focus entirely on the data, but rather, on how this data is being used. In designing your application you must determine the following:

•	Who will be using this application?

•	What are they trying to accomplish by using this application?

•	How will they be accomplishing these tasks?

You should involve the end-user as much as possible early in the design phase. This helps eliminate problems that can stem from misunderstandings about the purpose of the application. After you gain a better understanding of the tasks that the end-users of the application are trying to perform, you can then determine the data that is necessary to complete these tasks. In this step, you need to look at each task and decide:

•	What data must be available to perform this task?

•	How must this data be processed?

•	How can these results be meaningfully presented?

•	What are the potential future uses for this application?

It is important that your audience has a clear understanding of your proposed solution. It is also important that your application be designed to accommodate the changing needs of your audience.

________________________________________

Designing the Database

At this point, you are ready to begin designing your data model. This model will allow you to determine how your data can be most efficiently stored and utilized. The Entity-Relationship model is often used to map a real-world system to a relational database management system.

The Entity-Relationship model categorizes all elements of a system as either an entity (a person, place, or thing) or a relationship between entities. Both constructs are represented by the same structure, a table. For example, in an order-entry system, parts are entities, as are orders. Both part and order information is represented in tables. The relationship of which parts are requested by which order is also represented by a third table. The application of the Entity-Relationship model requires the following steps.

•	First, identify the entities of your system and construct a table to represent each entity.

•	Second, identify the relationships between the entities and either extend the current tables or create new tables to represent these relationships.

•	Third, identify attributes of each entity and extend the tables to include these attributes.

When modeling a system with the Entity-Relationship model, you will often include a step called normalization. Most texts on database design can instruct you on how to achieve Third Normal Form. Each table must have exactly one primary key, and in third normal form, all of the data in a table is dependent solely upon the table's primary key. You may, of course, find it necessary to violate normal form on occasion to achieve a desired efficiency level.

The proper application of the Entity-Relationship model results in well-designed tables. The benefits of a set of well-designed tables include:

•	reduced storage of redundant data, which eliminates the cost of updating duplicates and avoids the risk of inconsistent results based on duplicates

•	increased ability to effectively enforce integrity constraints

•	increased ability to adapt to the growth and change of the system

•	increased productivity based on the inherent flexibility of well-designed relational systems

Oracle's products for database design, CASE*Dictionary, CASE*Method, and CASE*Designer, can help improve, automate, and document designs. See the CASE manuals for additional information.

After determining the overall structure of the tables in your database, you must next design the content of these tables. This process involves selecting the proper datatype for each column and assigning each column a meaningful name. Information on selecting the appropriate ORACLE datatype is included in Chapter 3 of this document.

If you are creating an application to run on a distributed database, you must also determine where to locate this data and any links that are necessary to access the data across the network; see Chapter 11 for additional information.

________________________________________

Designing the Application

After completing your database design, you are ready to begin designing the application itself. This, too, is an iterative process, and may also cause you to rethink your database design. As much as possible, you should involve your audience in these design decisions. You should make your application available to the end-users as early as possible in order for them to provide you with the feedback needed to fine tune your design.

There are many tools available, from ORACLE as well as other vendors, to aid in the development and implementation of your application. Your first task is to evaluate the available tools and select those that are most appropriate.

Utilizing Available Features

You must next determine how to implement your requirements using the features available in ORACLE, as well as any other tools and utilities that you selected in the previous step. The features and tools that you choose to use to implement your application can significantly affect the performance of your application. The more effort that you put into designing an efficient application, the less time that you will have to spend tuning the application once it is complete.

Several of the more useful features available to ORACLE application developers are listed below. Each of these topics is discussed in detail later in this book.

 Integrity Constraints

Integrity constraints allow you to define certain requirements for the data that can be included in a table, and to ensure that these requirements are met regardless of how the data is entered. These constraints are included as part of the table definition, and require no programming to be enforced; see Chapter 6 for instructions on their use.

 Stored Procedures and Packages

Commonly used procedures can be written once in PL/SQL and stored in the database for repeated use by applications. This ensures consistent behavior among applications, and can reduce your development and testing time.

Related procedures can be grouped into packages, which can have a package specification separate from the package body. The package body can be altered and recompiled without affecting the package specification. This allows you to make changes to the package body that are not visible to end-users, and that do not require objects referencing the specification to be recompiled. See Chapter 7 for additional information.

 Database Triggers

Complex business rules that cannot be enforced using declarative integrity constraints can be enforced using triggers. Triggers, which are similar to stored procedures, are automatically executed when a triggering statement is issued, regardless of the user or application. See Chapter 8 for additional information.

Database triggers can have such diverse uses as performing value-based auditing, maintaining derived data values, enforcing complex security or integrity rules, and replicating data across databases. By moving this code from your application and into the database (via triggers), you can ensure that all applications behave in a uniform manner.

Cost-Based Optimizer

The cost-based optimization method uses the statistics about tables, along with information about the available indexes, to select an execution plan for SQL statements. This allows even inexperienced users to submit complex queries without having to worry about performance.

As an application designer, there may be times when you have knowledge of the data in your table that is not available to the optimizer, and that allows you to select a better execution path. In these cases, you can provide hints to the optimizer to allow it to select the proper execution path. See Chapter 5 for more information.

Shared SQL

Shared SQL allows multiple users to share a single run-time copy of procedures and SQL statements, significantly reducing memory requirements. If two identical SQL statements are issued, the shared SQL area used to process the first instance of the statement is reused for the processing of the subsequent instances of the same statement.

You should coordinate with your DBA, as well as other application developers, to establish guidelines to ensure that statements and blocks that perform similar tasks can use the same shared SQL areas as often as possible. See page 4 - 9 for additional information.

 National Language Support

ORACLE supports both single and multi-byte character encoding schemes. Because language-dependent data is stored separately from the code, you can easily add new languages and language-specific features (such as date formats) without altering your application code.

 Locking

By default, ORACLE provides row-level locking, allowing multiple users to access different rows of the same table without lock contention. Although this greatly reduces the chances of deadlocks occurring, you should still take care in designing your application to ensure that deadlocks do not occur.

Online transaction processing applications (that is, applications with multiple users concurrently modifying different rows of the same table) benefit the most from row-level locking. You should design your application with this feature in mind.

ORACLE locks are available to you for use within your applications, as well. These locks are provided as part of the DBMS_LOCK package, which is described in Appendix A.

 Profiles

Profiles can be used to enforce per-query and per-session limits on resource use. When designing your applications, you might want to consider if any users have been denied access to the system due to limited resources. By using profiles it may be possible to allow these infrequent users limited access to the database. If so, you may need to consider their requirements when formulating your design. Profiles are generally controlled by the database administrator. Consult your database administrator (DBA) to determine if access can be granted to additional users and to identify this audience.

 Sequences

You can use sequence numbers to automatically generate unique keys for your data, and to coordinate keys across multiple rows or tables. The sequence number generator eliminates the serialization caused by programmatically generating unique numbers by locking the most recently used value and then incrementing it. Sequence numbers can also be read from a sequence number cache, instead of disk, further increasing their speed.

 Industry Standards Compliance

ORACLE is designed to conform to industry standards. If your applications must conform to industry standards, you should consult the ORACLE7 Server SQL Language Reference manual for a detailed explanation of ORACLE's conformance to SQL standards.

________________________________________

Writing SQL

All operations performed on the information in an ORACLE database are executed using SQL statements. After you have completed the design of your application, you need to begin designing the SQL statements that you will use to implement this design. You should have a thorough understanding of SQL before you begin to write your application. A general description of how SQL statements are executed is provided in Chapter 4 of this document. For more detailed information, see the ORACLE7 Server SQL Language Reference Manual.

You can significantly improve the performance of your application by tuning the SQL statements it uses. Tuning SQL statements is explained in detail in Chapter 5 of this document.

________________________________________

Enforcing Security in Your Application

Your application design is not complete until you have determined the security requirements for the application. As part of your application design, you identified what tasks each user or group of users needed to perform. You now need to determine what privileges these users need to perform these tasks. It is important to the security of the database that these users be granted no more access than is necessary to complete their tasks.

By having your application enable the appropriate roles when a user runs the application, you can ensure that the user can only access the database as you originally planned. Because roles are typically granted to users by the database administrator, you should coordinate with your DBA to ensure that each user is granted access to the roles required by your application for a designated task. See Chapter 10.

________________________________________

Tuning an Application

There are two important areas to think about when tuning your database application:

•	tuning your SQL statements

•	tuning your application design

Information on tuning your SQL statements, including how to use the cost-based optimization method, is included in Chapter 5 "Tuning SQL Statements" of this book. Tuning your application design ideally occurs before you begin to implement your application. Before beginning your design, you should carefully read about each of the features described in this document and consider which features best suit your requirements. Some design decisions that you should consider are outlined below.

•	Enforce business rules with integrity constraints instead of programmatically. See page 6 - 2 for a discussion of when to use integrity constraints.

•	Use PL/SQL instead of SQL to improve performance. A description of how PL/SQL improves performance is included on page 4 - 23.

•	To further improve performance, and reduce runtime recompilations, use packages, which are described on page 7 - 2.

•	Use cached sequence numbers to generate primary key values; see page 2 - 14.

•	Use array processing to reduce the number of calls to ORACLE; see page 4 - 19.

•	Use VARCHAR2 to store character data instead of CHAR, which blank-pads data; see page 3 - 3.

•	Store LONG and LONG RAW data in tables separate from related data and use referential integrity to relate them. This allows you to access the related data without having to read the LONG or LONG RAW data; see page 3 - 6.

You should also work with your database administrator to determine how the database can be tuned to accommodate your application. Database tuning is discussed in the ORACLE7 Server Administrator's Guide.

________________________________________

Maintaining and Updating an Application

If you are upgrading an existing application, or writing a new application to run on an existing database, you must follow many of the same procedures described earlier in this section. You must identify and understand the needs of your audience and design your application to accommodate them.

You must also work closely with the database administrator to determine the following:

•	what existing applications are available and how they are being used

•	what data is available, if any can be eliminated, or if any additional data must be collected

•	if any modifications must be made to the database structure, and how to make these changes in the least disruptive manner


CHAPTER 2. MANAGING SCHEMA OBJECTS

This chapter discusses the procedures necessary to create and manage the different types of objects contained in a user's schema. The topics included are:

•	the procedures to create, manage, and drop schema objects

•	renaming schema objects

•	the procedures for managing the space usage of data blocks

•	name resolution of schema objects

Note: Procedures, functions, and packages are discussed in Chapter 7, dependency information is in Chapter 9, and snapshots are covered in Chapter 12. If you are using Trusted ORACLE, there are additional privileges required and issues to consider when managing schema objects; refer to the Trusted ORACLE7 Server Administrator's Guide.

________________________________________

Managing Tables

A table is the data structure that holds data in a relational database. A table is comprised of rows and columns.

A table can represent a single entity that you want to track within your system. Such a table might represent a list of the employees within your organization or the orders placed for your company's products.

A table can also represent a relationship between two entities. Such a table could be used to 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 might both represent 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 table describes the employees in a firm, but this table also includes a foreign key column, DEPTNO, which represents 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 the ORACLE7 Server Administrator's Guide for more suggestions. You should also refer to a text on relational database or table design.

Designing Tables

You should consider the following guidelines when designing your tables.

•	Use descriptive names for tables, columns, indexes, and clusters.

•	Be consistent in abbreviation 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 proper datatype for each column.

•	Define 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 defined on the columns of a table to enforce the business rules of your database automatically; see Chapter 6 for guidelines.

Creating Tables

To create a table, use the SQL command CREATE TABLE. For example, if the user SCOTT issues the following statement, he creates a non-clustered table named EMP in his schema that is physically stored in the USERS tablespace. Notice that integrity constraints are defined on several columns of the table.

CREATE TABLE emp (

   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)

   PCTFREE 10

   PCTUSED 40

   TABLESPACE users

   STORAGE (  INITIAL 50K

              NEXT 50K

              MAXEXTENTS 10

              PCTINCREASE 25 );

 Managing the Space Usage of Data Blocks

The following sections explain how to use the PCTFREE and PCTUSED parameters to do the following tasks:

•	increase the performance of writing and retrieving a data or index segment

•	decrease the amount of unused space in data blocks

•	decrease the amount of row chaining between data blocks

 Specifying PCTFREE

The PCTFREE default is 10 percent; any integer from 0 to 99 is acceptable, as long as the sum of PCTFREE and PCTUSED does not exceed 100. (If PCTFREE is set to 99, ORACLE puts at least one row in each block, regardless of row size. If rows are very small and blocks very large, even more than one row might fit.)

A lower PCTFREE:

•	reserves less room for updates to existing table rows

•	allows inserts to fill the block more completely

•	might save space, because the total data for a table or index is stored in fewer blocks (more rows or entries per block)

•	increases processing costs because blocks frequently need to be reorganized as their free space area becomes filled with new or updated data

•	potentially increases processing costs and space required if updates to rows or index entries cause rows to grow and span blocks (because UPDATE, DELETE, and SELECT statements might need to read more blocks for a given row and because chained row pieces contain references to other pieces)

A higher PCTFREE:

•	reserves more room for future updates to existing table rows

•	might require more blocks for the same amount of inserted data (inserting fewer rows per block)

•	lessens processing costs because blocks infrequently need reorganization of their free space area

•	might improve update performance, because ORACLE must chain row pieces less frequently, if ever

In setting PCTFREE, you should understand the nature of the table or index data. Updates can cause rows to grow. New values might not be the same size as values they replace. If there are many updates in which data values get longer, increase PCTFREE; if updates to rows do not affect the total row width, then PCTFREE can be low.

Your goal is to find a satisfactory tradeoff between densely packed data (low PCTFREE, full blocks) and good update performance (high PCTFREE, less-full blocks).

PCTFREE also affects the performance of a given user's queries on tables with uncommitted transactions belonging to other users. Assuring read consistency might cause frequent reorganization of data in blocks that have little free space.

PCTFREE for Non-Clustered Tables     If the data in the rows of a non-clustered table is likely to increase in size over time, reserve space for these updates. If you do not reserve room for updates, updated rows are likely to be chained between blocks, reducing I/O performance associated with these rows.

PCTFREE for Clustered Tables     The discussion for non-clustered tables also applies to clustered tables. However, if PCTFREE is reached, new rows from any table contained in the same cluster key go into a new data block chained to the existing cluster key.

PCTFREE for Indexes     Indexes infrequently require the use of free space for updates to index data. Therefore, the PCTFREE value for index segment data blocks is normally very low (for example, 5 or less).

 Specifying PCTUSED

Once the percentage of free space in a data block reaches PCTFREE, no new rows are inserted in that block until the percentage of space used falls below PCTUSED. ORACLE tries to keep a data block at least PCTUSED full. The percent is of block space available for data after overhead is subtracted from total space,

The default for PCTUSED is 40 percent; any integer between 0 and 99, inclusive, is acceptable as long as the sum of PCTUSED and PCTFREE does not exceed 100.

A lower PCTUSED:

•	usually keeps blocks less full than a higher PCTUSED

•	reduces processing costs incurred during UPDATE and DELETE statements for moving a block to the free list when the block has fallen below that percentage of usage

•	increases the unused space in a database

 A higher PCTUSED:

•	usually keeps blocks fuller than a lower PCTUSED

•	improves space efficiency

•	increases processing cost during INSERTs and UPDATEs

 Choosing Associated PCTUSED and PCTFREE Values

If you decide not to use the default values for PCTFREE and PCTUSED, use the following guidelines.

•	The sum of PCTFREE and PCTUSED must be equal to or less than 100.

•	If the sum is less than 100, the ideal compromise of space utilization and I/O performance is a sum of PCTFREE and PCTUSED that differs from 100 by the percentage of space in the available block that an average row occupies. For example, assume that the data block size is 2048 bytes, minus 100 bytes of overhead, leaving 1948 bytes available for data. If an average row requires 195 bytes, or 10% of 1948, then an appropriate combination of PCTUSED and PCTFREE that sums to 90% would make the best use of database space.

•	If the sum equals 100, ORACLE attempts to keep no more than PCTFREE free space, and the processing costs are highest.

•	Fixed block overhead is not included in the computation of PCTUSED or PCTFREE.

•	The smaller the difference between 100 and the sum of PCTFREE and PCTUSED (as in PCTUSED of 75, PCTFREE of 20), the more efficient space usage is at some performance cost.

 Examples of Choosing PCTFREE and PCTUSED Values

The following examples illustrate correctly specifying values for PCTFREE and PCTUSED in given scenarios.

Example 1	Scenario:	Common activity includes UPDATE statements that increase the size of the rows. Performance is important.

Settings:	PCTFREE = 20

PCTUSED = 40

Explanation:	PCTFREE is set to 20 to allow enough room for rows that increase in size as a result of updates. PCTUSED is set to 40 so that less processing is done during high update activity, thus improving performance.

Example 2	Scenario:	Most activity includes INSERT and DELETE statements, and UPDATE statements that do not increase the size of affected rows. Performance is important.

Settings:	PCTFREE = 5

PCTUSED = 60

Explanation:	PCTFREE is set to 5 because most UPDATE statements do not increase row sizes. PCTUSED is set to 60 so that space freed by DELETE statements is used relatively soon, yet the amount of processing is minimized.

Example 3	Scenario:	The table is very large; therefore, storage is a primary concern. Most activity includes read-only transactions; therefore, query performance is important.

Settings:	PCTFREE = 5

PCTUSED = 90

Explanation:	PCTFREE is set to 5 because UPDATE statements are rarely issued. PCTUSED is set to 90 so that more space per block is used to store table data. This setting for PCTUSED reduces the number of data blocks required to store the table's data and decreases the average number of data blocks to scan for queries, thereby increasing the performance of queries.

Privileges Required to Create a Table     To create a new table in your schema, you must have the CREATE TABLE system privilege. To create a table in another user's schema, you must have the CREATE ANY TABLE system privilege. Additionally, the owner of the table must have a quota for the tablespace that contains the table, or the UNLIMITED TABLESPACE system privilege.

Altering Tables

You might alter a table in an ORACLE database for any of the following reasons:

•	to add one or more new columns to the table

•	to add one or more integrity constraints to a table

•	to modify an existing column's definition (datatype, length, default value, and NOT NULL integrity constraint)

•	to modify data block space usage parameters (PCTFREE, PCTUSED)

•	to modify transaction entry settings (INITRANS, MAXTRANS)

•	to modify storage parameters (NEXT, PCTINCREASE, etc.)

•	to enable or disable integrity constraints or triggers associated with the table

•	to drop integrity constraints associated with the table

When altering the column definitions of a table, you can only increase the length of an existing column, unless the table has no records. You can also decrease the length of a column in an empty table. For columns of datatype CHAR, increasing the length of a column might be a time consuming operation that requires substantial additional storage, especially if the table contains many rows. This is because the CHAR value in each row must be blank-padded to satisfy the new column length.

Use the SQL command ALTER TABLE to alter a table, as in:

ALTER TABLE emp

   PCTFREE 30

   PCTUSED 60;

Altering a table has the following implications:

•	If a new column is added to a table, the column is initially null. You can add a column with a NOT NULL constraint to a table only if the table does not contain any rows.

•	If a view or PL/SQL program unit depends on a base table, the alteration of the base table might affect the dependent object, and always invalidates the dependent object.

Privileges Required to Alter a Table     To alter a table, the table must be contained in your schema, or you must have either the ALTER object privilege for the table or the ALTER ANY TABLE system privilege.

Dropping Tables

Use the SQL command DROP TABLE to drop a table. For example, the following statement drops the EMP table:

DROP TABLE emp;

If the table that you are dropping contains any primary or unique keys referenced by foreign keys of other tables, and you intend to drop the FOREIGN KEY constraints of the child tables, include the CASCADE option in the DROP TABLE command, as in:

DROP TABLE emp CASCADE CONSTRAINTS;

Dropping a table has the following effects:

•	Dropping a table removes the table definition from the data dictionary. All rows of the table are then inaccessible.

•	All indexes and triggers associated with the table are dropped.

•	All views and PL/SQL program units that depend on a dropped table remain, yet become invalid (not usable).

•	All synonyms for a dropped table remain, but return an error when used.

•	All extents allocated for a non-clustered table that is dropped are returned to the free space of the tablespace and can be used by any other object requiring new extents.

•	All rows corresponding to a clustered table are deleted from the blocks of the cluster.

•	If the table is a master table for snapshots, ORACLE does not drop the snapshots, but does drop the snapshot log. The snapshots can still be used, but they cannot be refreshed unless the table is recreated.

If you want to delete all of the rows of a table, but keep the table definition, you should use the TRUNCATE TABLE command. This command is described in the ORACLE7 Server Administrator's Guide.

Privileges Required to Drop a Table   ..To drop a table, the table must be contained in your schema or you must have the DROP ANY TABLE system privilege.

________________________________________

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 provide a means to present 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 several SQL commands.

Creating Views

Use the SQL command CREATE VIEW to create a view. You can define views with any query that references tables, snapshots, or other views; however, the query that defines a view cannot contain the ORDER BY or FOR UPDATE clauses. For example, the following statement creates a view on a subset of data in the EMP table:

CREATE VIEW sales_staff AS

   SELECT empno, ename, deptno

   FROM emp

   WHERE deptno = 10

   WITH CHECK OPTION CONSTRAINT sales_staff_cnst;

The query that defines the SALES_STAFF view references only rows in department 10. Furthermore, the 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. Considering the example above, the following INSERT statement successfully inserts a row into the EMP table via the SALES_STAFF view; that is, all rows with department number 10 can be selected using 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 and DEPT tables:

CREATE VIEW division1_staff AS

   SELECT ename, empno, job, dname

   FROM emp, dept

   WHERE emp.deptno IN (10, 30)

   AND emp.deptno = dept.deptno;

The DIVISION1_STAFF view is defined by a query that joins information from the EMP and DEPT tables. The WITH CHECK OPTION is not specified in the CREATE VIEW statement because rows cannot be inserted into or updated in a view defined with a query that contains a join; see page .

Expansion of Defining Queries at View Creation Time     In accordance with the ANSI/ISO standard, ORACLE expands any wildcard in a top-level view query into a column list when a view is created and stores the resulting query in the data dictionary; any subqueries are left intact. The column names in an expanded column list are enclosed in quote marks to account for the possibility that the columns of the base object were originally entered with quotes and require them for the query to be syntactically correct.

As an example, assume that the DEPT view is created as follows:

CREATE VIEW dept AS SELECT * FROM scott.dept;

ORACLE stores the defining query of the DEPT view as:

SELECT "DEPTNO", "DNAME", "LOC" FROM scott.dept

Views created with errors do not have wildcards expanded. However, if the view is eventually compiled without errors, wildcards in the defining query are expanded.

 Creating Views with Errors

Assuming no syntax errors, a view can be created (with errors) even if the defining query of the view cannot be executed. For example, if a view is created that refers to a non-existent table or an invalid column of an existing table, or if the owner of the view does not have the required privileges, the view can still be created and entered into the data dictionary.

You can only create a view with errors by using the FORCE option of the CREATE VIEW command:

CREATE FORCE VIEW AS ...;

When a view is created with errors, ORACLE returns a message that indicates the view was created with errors. The status of such a view is left as INVALID. If conditions later change so that the query of an invalid view can be executed, the view can be recompiled and become valid.

 Privileges Required to Create a View

To create a view, you must have been granted the following privileges:

•	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 user's schema. These privileges can be acquired explicitly or via a role.

•	The owner of the view must have been explicitly granted the necessary privileges to access all objects referenced within the definition of the view; the owner cannot have obtained the required privileges through roles. Also, the functionality of the view is dependent on the privileges of the view's owner. For example, if you (the view owner) are granted only the INSERT privilege for Scott's EMP table, you can create a view on his EMP table, but you can only use this view to insert new rows into the EMP table.

•	If the view owner intends to grant access to the view to other users, the owner must have received the object privileges to the base objects with the GRANT OPTION or the system privileges with the ADMIN OPTION; if not, you have insufficient privileges to grant access to the view to other users.

Replacing Views

If the definition of a view must be altered, the view must be replaced. Views can be replaced in two different ways:

•	A view can be dropped and then recreated. When a view is dropped, all grants of corresponding view privileges are revoked from roles and users. After the view is recreated, necessary privileges must be regranted.

•	A view can be replaced by redefining it with a CREATE VIEW statement that contains the OR REPLACE option. This option is used to replace the current definition of a view but preserve 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 redefine the SALES_STAFF view to correct the department number specified in the WHERE clause of the defining 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

   WHERE deptno = 30

   WITH CHECK OPTION CONSTRAINT sales_staff_cnst;

Replacing a view has the following effects:

•	Replacing a view replaces the view's definition in the data dictionary. All underlying objects referenced by the view are not affected.

•	If previously defined but not included in the new view definition, the constraint associated with the WITH CHECK OPTION for a view's definition is dropped.

•	All views and PL/SQL program units dependent on a replaced view become invalid (not useable).

 Privileges Required to Replace a View

To replace a view, you must have all of the privileges needed to drop the view, as well as all of those required to create the view.

Using Views

Views can be queried in the same manner as tables. For example, to query the DIVISION1_STAFF view, enter a valid SELECT statement that references the view:

SELECT * FROM division1_staff;

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 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 following order:

1.	If a view is defined by a query that contains a join operation, SET or DISTINCT operators, a GROUP BY clause, or a group function, rows cannot be inserted into, updated in, or deleted from the base tables using the view.

2.	If a view is defined with the WITH CHECK OPTION, 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.

3.	If a NOT NULL column that does not have a DEFAULT clause is omitted from the view, a row cannot be inserted into the base table using the view.

4.	If the view was created by using an expression, such as DECODE(deptno, 10, 'SALES', ...), rows cannot be inserted into or updated in the base table using the view.

For example, DML statements cannot be issued against the DIVISION1_STAFF view because the view is defined by a query that contains a join operation. The constraint created by the 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 table. Alternatively, assume that the SALES_STAFF view is defined by the following statement (that is, excluding the DEPTNO column):

CREATE VIEW sales_staff AS

   SELECT empno, ename

   FROM emp

   WHERE deptno = 10

   WITH CHECK OPTION CONSTRAINT sales_staff_cnst;

Considering this view definition, you can update the EMPNO or ENAME fields of existing records, but you cannot insert rows into the EMP table via the SALES_STAFF view because the view does not let you alter the DEPTNO field. If you had defined a DEFAULT value of 10 on the DEPTNO field, 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 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).

 Privileges Required to Use a View

To issue a query or an INSERT, UPDATE, or DELETE statement against a view, you must have the SELECT, INSERT, UPDATE, or DELETE object privilege for the view, respectively, either explicitly or via a role.

Dropping Views

Use the SQL command DROP VIEW to drop a view, as in:

DROP VIEW sales_staff;

 Privileges Required to Drop a View

You can drop any view contained in your schema. To drop a view in another user's schema, you must have the DROP ANY VIEW system privilege.

________________________________________

Managing Sequences

The sequence generator generates sequential numbers. Sequence number generation is useful to generate unique primary keys for your data 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, 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. Instructions for tuning your sequences start on page 2 - 17.

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 table:

CREATE SEQUENCE emp_sequence

   INCREMENT BY 1

   START WITH 1

   NOMAXVALUE

   NOCYCLE

   CACHE 10;

Notice that several parameters can be specified 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.

For additional implications for caching sequence numbers when using the ORACLE Parallel Server, see the ORACLE7 Parallel Server Administrator's Guide. General information about caching sequence numbers is included on page 2 - 17.

 Privileges Required to Create a Sequence

To create a sequence in your schema, you must have the CREATE SEQUENCE system privilege. To create a sequence in another user's schema, you must have the CREATE ANY SEQUENCE privilege.

Altering Sequences

You can change any of the parameters that define how corresponding sequence numbers are generated; however, you cannot alter a sequence to change the starting number of a sequence. To do this, the sequence must be dropped and recreated.

Use the SQL command ALTER SEQUENCE to alter a sequence, as in:

ALTER SEQUENCE emp_sequence

   INCREMENT BY 10

   MAXVALUE 10000

   CYCLE

   CACHE 20;

Privileges Required to Alter a Sequence     To alter a sequence, your schema must contain the sequence, or you must have the ALTER ANY SEQUENCE system privilege.

Using Sequences

The following sections provide some information on how to use a sequence once it has been defined. Once defined, a sequence can be made available to many users. A sequence 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 (master table) and LINE_ITEMS (detail table), that hold information about customer orders. A sequence named ORDER_SEQ is defined 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 pseudo-columns; each new sequence number is generated by a reference to the sequence's pseudo-column 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, as in:

INSERT INTO orders (orderno, custno)

   VALUES (order_seq.NEXTVAL, 1032);

or in the SET clause of an UPDATE statement, as in:

UPDATE orders

   SET orderno = order_seq.NEXTVAL

   WHERE orderno = 10112;

or the outermost SELECT of a query or subquery, as in:

SELECT order_seq.NEXTVAL FROM dual;

As defined, the first 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 per row; that is, if NEXTVAL is referenced more than once in a single statement, the first 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, 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 finish placing the customer's order by inserting the line items for the order:

INSERT INTO line_items (orderno, partno, quantity)

   VALUES (order_seq.CURRVAL, 20321, 3);

INSERT INTO line_items (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:

•	VALUES clause of INSERT statements

•	the SELECT list of a SELECT statement

•	the SET clause of an UPDATE statement

CURRVAL and NEXTVAL cannot be used in these places:

•	a subquery

•	a view's query or snapshot's query

•	a SELECT statement with the DISTINCT operator

•	a SELECT statement with a GROUP BY or ORDER BY clause

•	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

Caching Sequence Numbers

Sequence numbers can be kept in the sequence cache in the System Global Area (SGA). Sequence numbers can be accessed more quickly in the sequence cache than they can be read from disk.

The sequence cache consists of entries. Each entry can hold many sequence numbers for a single sequence.

Follow these guidelines for fast access to all sequence numbers:

•	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, the sequence must be read from disk to the cache before the sequence numbers are used.

If your applications use many sequences concurrently, 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 entries in the sequence cache is determined by the initialization parameter SEQUENCE_CACHE_ENTRIES. The default value for this parameter is 10 entries. ORACLE creates and uses sequences internally for auditing, grants of system privileges, grants of object privileges, profiles, debugging stored procedures, and labels. Be sure your sequence cache has enough entries to hold these sequences as well as sequences used by your applications.

If the value for your SEQUENCE_CACHE_ENTRIES parameter is too low, it is possible to skip sequence values. For example, assume that this parameter is set to 4, and that you currently have four cached sequences. If you create a fifth sequence, it will replace the least recently used sequence in the cache. All of the remaining values in this displaced sequence are lost. That is, if the displaced sequence originally held 10 cached sequence values, and only one had been used, nine would be lost when the sequence was displaced.

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

The first 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 allows you to access more successive sequence numbers with fewer reads from disk to the sequence cache. However, in the event of instance failure, 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, 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

 Privileges Required to Use a Sequence

To use a sequence, your schema must contain the sequence or you must have been granted the SELECT object privilege for another user's sequence.

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 definition is removed from the data dictionary. Any synonyms for the sequence remain, but return an error when referenced.

Privileges Required to Drop a Sequence     You can drop any sequence in your schema. To drop a sequence in another schema, you must have the DROP ANY SEQUENCE system privilege.

________________________________________

Managing Synonyms

A synonym is an alias for a table, view, snapshot, sequence, procedure, function, or package. 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 table contained in the schema of JWARD:

CREATE PUBLIC SYNONYM public_emp FOR jward.emp;

 Privileges Required to Create a Synonym

You must have the CREATE SYNONYM system privilege to create a private synonym in your schema, or the CREATE ANY SYNONYM system privilege to create a private synonym in another user's schema. To create a public synonym, you must have the CREATE PUBLIC SYNONYM system privilege.

Using Synonyms

A synonym can be referenced in a SQL statement the same way that the underlying object of the synonym can be referenced. For example, if a synonym named EMP refers to a table or view, the following statement is valid:

INSERT INTO emp (empno, ename, job)

   VALUES (emp_sequence.NEXTVAL, 'SMITH', 'CLERK');

If the synonym named FIRE_EMP refers to a stand-alone procedure or package procedure, it could be used in the following context:

EXECUTE fire_emp(7344);

 Privileges Required to Use a Synonym

You can successfully use any private synonym contained in your schema or any public synonym, assuming that you have the necessary privileges to access the underlying object, either explicitly, from an enabled role, or from PUBLIC. You can also reference any private synonym contained in another schema if you have been granted the necessary object privileges for the private synonym. You can only reference another user's synonym using the object privileges that you have been granted. For example, if you have the SELECT privilege for the JWARD.EMP synonym, you can query the JWARD.EMP synonym, but you cannot insert rows using JWARD.EMP.

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:

DROP SYNONYM emp;

The following statement drops the public synonym named PUBLIC_EMP:

DROP PUBLIC SYNONYM public_emp;

When you drop a synonym, its definition is removed from the data dictionary. All objects that reference a dropped synonym remain (for example, views and procedures) but become invalid.

 Privileges Required to Drop a Synonym

You can drop any private synonym in your own schema. To drop a private synonym in another user's schema, you must have the DROP ANY SYNONYM system privilege. To drop a public synonym, you must have the DROP PUBLIC SYNONYM system privilege.

________________________________________

Managing Indexes

Indexes are used in ORACLE to provide quick access to rows in a table. Indexes provide faster access to data for operations that return a small portion of a table's rows.

ORACLE does not limit the number of indexes you can create on a table. However, you should consider the performance benefits of indexes and the needs of your database applications to determine which columns to index.

The following sections explain how to create, alter, and drop indexes using SQL commands. Some simple guidelines to follow when managing indexes are included; see page 5 - 2, "How to Use Indexes", for performance implications of index creation.

 Create Indexes After Inserting Table Data

With one notable exception, you should usually create indexes after you have inserted or loaded (using SQL*Loader or Import) data into a table. It is more efficient to insert rows of data into a table that has no indexes and then to create the indexes for subsequent queries, etc. If you create indexes before table data is loaded, every index must be updated every time you insert a row into the table. The exception to this rule is that you must create an index for a cluster before you insert any data into the cluster.

When you create an index on a table that already has data, ORACLE must use sort space to create the index. ORACLE uses the sort space in memory allocated for the creator of the index (the amount per user is determined by the initialization parameter SORT_AREA_SIZE), but must also swap sort information to and from temporary segments allocated on behalf of the index creation. If the index is extremely large, it might be beneficial to complete the following steps:

1.	Create a new temporary tablespace, using the CREATE TABLESPACE command.

2.	Use the TEMPORARY TABLESPACE option of the ALTER USER command to make this your new temporary tablespace.

3.	Create the index using the CREATE INDEX command.

4.	Drop this tablespace using the DROP TABLESPACE command. Then use the ALTER USER command to reset your temporary tablespace to your original temporary tablespace.

Under certain conditions, you can load data into a table with SQL*Loader's "direct path load," and an index can be created as data is loaded; refer to the ORACLE7 Server Utilities User's Guide for more information.

Index the Correct Tables and Columns     Use the following guidelines for determining when to create an index:

•	Create an index if you frequently want to retrieve less than 1-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 and the more clustered the row data, the higher the percentage.

•	Index columns used for joins to improve performance on joins of multiple tables.

Note: Primary and unique keys automatically have indexes, but you might want to create an index on a foreign key; see "Concurrency Control, Indexes, and Foreign Keys" on page 6 - 9 for more information.

•	Small tables do not require indexes; if a query is taking too long, 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:

•	Values are relatively unique in the column.

•	There is a wide range of values.

•	The column contains many nulls, but queries often select all rows having a value. In this case, the phrase:

WHERE COL_X > -9.99 x 10!!super!!-125

is preferable to:

WHERE COL_X IS NOT NULL

because the first uses an index on COL_X (assuming that COL_X is a numeric column).

Columns with the following characteristics are less suitable for indexing:

•	The column has few distinct values (for example, a column for the sex of employees).

•	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-third of the data block size. Consult with the database administrator for assistance in determining the space required by an index.

Limit the Number of Indexes per Table     A table can have any number of indexes. However, the more indexes, the more overhead is incurred as the table is altered. When rows are inserted or deleted, all indexes on the table must be updated. When a column is updated, all indexes on the column must be updated.

Thus, there is a tradeoff between speed of retrieval for queries on a table and speed of accomplishing updates on the table. For example, if a table is primarily read-only, more indexes might be useful, but if a table is heavily updated, fewer indexes might be preferable.

Order Index Columns for Performance     The order in which columns are named in the CREATE INDEX command need not correspond to the order in which they appear in the table. However, the order of columns in the CREATE INDEX statement is significant because query performance can be affected by the order chosen. In general, you should put the column expected to be used most often first in the index.

For example, assume the columns of the VENDOR_PARTS table are as shown in Figure 2 - 1.

Assume that there are five vendors, and each vendor has about 1000 parts.

Suppose that the VENDOR_PARTS table is commonly queried by SQL statements such as the following example:

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 first; that is, the column with the most values:

CREATE INDEX ind_vendor_id

   ON vendor_parts (part_no, vendor_id);

Indexes speed retrieval on any query using 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 five distinct values, placing a separate index on VENDOR_ID would serve no purpose.

Creating Indexes

You can create an index for a table to improve the performance of queries issued against the corresponding table. You can also create an index for a cluster. You can create a composite index on multiple columns up to a maximum of 16 columns.

ORACLE automatically creates an index to enforce a UNIQUE or PRIMARY KEY integrity constraint. In general, it is better to create such constraints to enforce uniqueness and not explicitly use the obsolete CREATE UNIQUE INDEX syntax.

Use the SQL command CREATE INDEX to create an index. The following statement creates an index named EMP_ENAME for the ENAME column of the EMP table:

CREATE INDEX emp_ename ON emp(ename)

   TABLESPACE users

   STORAGE (INITIAL 20K

            NEXT 20k

            PCTINCREASE 75)

   PCTFREE 0;

Notice that several storage settings are explicitly specified for the index.

 Privileges Required to Create An Index

To create a new index you must own, or have the INDEX object privilege for, the corresponding table. The schema that contains the index must also have a quota for the tablespace intended to contain the index, or the UNLIMITED TABLESPACE system privilege. To create an index in another user's schema, you must have the CREATE ANY INDEX system privilege.

Dropping Indexes

You might drop an index for the following reasons:

•	The index is not providing anticipated performance improvements for queries issued against the associated table (the table is very small, or there are many rows in the table but very few index entries, etc.).

•	Applications do not contain queries that use the index.

•	The index is no longer needed and must be dropped before being rebuilt.

When you drop an index, all extents of the index's 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, to drop the EMP_ENAME index, enter the following statement:

DROP INDEX emp_ename;

If you drop a table, all associated indexes are dropped.

Privileges Required to Drop an Index     To drop an index, the index must be contained in your schema or you must have the DROP ANY INDEX system privilege.

________________________________________

Managing Clusters, Clustered Tables, and Cluster Indexes

Because clusters store related rows of different tables together in the same data blocks, two primary benefits are achieved when clusters are properly used:

•	Disk I/O is reduced and access time improves for joins of clustered tables.

•	In a cluster, a cluster key value (that is, the related value) is only stored once, no matter how many rows of different tables contain the value. Therefore, less storage may be required to store related table data in a cluster than is necessary in non-clustered table format.

Guidelines for Creating Clusters

Some guidelines for creating clusters are outlined below. For performance characteristics, see "How to Use Clusters" on page 5 - 7.

Choose Appropriate Tables to Cluster   Use clusters to store one or more tables that are primarily queried (not predominantly inserted into or updated), and for which queries often join data of multiple tables in the cluster or retrieve related data from a single table.

Choose Appropriate Columns for the Cluster Key      Choose cluster key columns carefully. If multiple columns are used in queries that join the tables, make the cluster key a composite key. In general, the same column characteristics that make a good index apply for cluster indexes; see "Index the Correct Tables and Columns" on page 2 - 22 for more information about these guidelines.

A good cluster key has enough unique values so that the group of rows corresponding to each key value fills approximately one data block. Too few rows per cluster key value can waste space and result in negligible performance gains. Cluster keys that are so specific that only a few rows share a common value can cause wasted space in blocks, unless a small SIZE was specified at cluster creation time.

Too many rows per cluster key value can cause extra searching to find rows for that key. Cluster keys on values that are too general (for example, MALE and FEMALE) result in excessive searching and can result in worse performance than with no clustering.

A cluster index cannot be unique or include a column defined as LONG.

Performance Considerations

It should also be noted that clusters can reduce the performance of DML statements (INSERTs, UPDATEs, and DELETEs) as compared to storing a table separately with its own index. These disadvantages relate to the use of space and the number of blocks that must be visited to scan a table; because multiple tables have data in each block (that is, they share each block), more blocks must be used to store a clustered table than if that same table were stored non-clustered. You should make your decisions about using clusters with these tradeoffs in mind.

To identify data that would be better stored in clustered form than non-clustered, look for tables that are related via referential integrity constraints and tables that are frequently accessed together using SELECT statements that join data from two or more tables. If you cluster tables on the columns used to join table data, you reduce the number of data blocks that must be accessed to process the query; all the rows needed for a join on a cluster key are in the same block. Therefore, query performance for joins is improved. Similarly, it may be useful to cluster an individual table. For example, the EMP table could be clustered on the DEPTNO column to cluster the rows for employees in the same department. This would be advantageous if applications commonly process rows, department by department.

Like indexes, clusters do not affect application design. The existence of a cluster is transparent to users and to applications. Data stored in a clustered table is accessed via SQL just like data stored in a non-clustered table.

Creating Clusters, Clustered Tables, and Cluster Indexes

Use a cluster to store one or more tables that are frequently joined in queries. Do not use a cluster to cluster tables that are frequently accessed individually.

Once you create a cluster, tables can be created in the cluster. However, before you can insert any rows into the clustered tables, you must create a cluster index. The use of clusters does not affect the creation of additional indexes on the clustered tables; you can create and drop them as usual.

Use the SQL command CREATE CLUSTER to create a cluster. The following statement creates a cluster named EMP_DEPT, which stores the EMP and DEPT tables, clustered by the DEPTNO column:

CREATE CLUSTER emp_dept (deptno NUMBER(3))

   PCTUSED 80

   PCTFREE 5;

Create a table in a cluster using the SQL command CREATE TABLE with the CLUSTER option. For example, the EMP and DEPT tables can be created in the EMP_DEPT cluster using the following statements:

CREATE TABLE dept (

   deptno NUMBER(3) PRIMARY KEY,

   . . . )

   CLUSTER emp_dept (deptno);

CREATE TABLE emp (

   empno NUMBER(5) PRIMARY KEY,

   ename VARCHAR2(15) NOT NULL,

   . . .

   deptno NUMBER(3) REFERENCES dept)

   CLUSTER emp_dept (deptno);

A table created in a cluster is contained in the schema specified in the CREATE TABLE statement; a clustered table might not be in the same schema that contains the cluster.

You must create a cluster index before any rows can be inserted into any clustered table. For example, the following statement creates a cluster index for the EMP_DEPT cluster:

CREATE INDEX emp_dept_index

   ON CLUSTER emp_dept

   INITRANS 2

   MAXTRANS 5

   PCTFREE 5;

Note: A cluster index cannot be unique. Furthermore, ORACLE is not guaranteed to enforce uniqueness of columns in the cluster key if they have UNIQUE or PRIMARY KEY constraints.

The cluster key establishes the relationship of the tables in the cluster.

 Privileges Required to Create a Cluster, Clustered Table, and Cluster Index

To create a cluster in your schema, you must have the CREATE CLUSTER system privilege, and a quota for the tablespace intended to contain the cluster or the UNLIMITED TABLESPACE system privilege. To create a cluster in another user's schema, you must have the CREATE ANY CLUSTER system privilege, and the owner must have a quota for the tablespace intended to contain the cluster or the UNLIMITED TABLESPACE system privilege.

To create a table in a cluster, you must have either the CREATE TABLE or CREATE ANY TABLE system privilege. You do not need a tablespace quota or the UNLIMITED TABLESPACE system privilege to create a table in a cluster.

To create a cluster index, your schema must contain the cluster, and you must have the following privileges:

•	the CREATE ANY INDEX system privilege or, if you own the cluster, the CREATE INDEX privilege

•	a quota for the tablespace intended to contain the cluster index, or the UNLIMITED TABLESPACE system privilege

Manually Allocating Storage for a Cluster

ORACLE dynamically allocates additional extents for the data segment of a cluster, as required. In some circumstances, you might want to explicitly allocate an additional extent for a cluster. For example, when using the ORACLE Parallel Server, an extent of a cluster can be allocated explicitly for a specific instance.

You can allocate a new extent for a cluster using the SQL command ALTER CLUSTER with the ALLOCATE EXTENT option; see the ORACLE7 Parallel Server Administrator's Guide for more information.

Dropping Clusters, Clustered Tables, and Cluster Indexes

Drop a cluster if the tables currently within the cluster are no longer necessary. When you drop a cluster, the tables within the cluster and the corresponding cluster index are dropped; all extents belonging to both the cluster's data segment and the index segment of the cluster index are returned to the containing tablespace and become available for other segments within the tablespace.

You can individually drop clustered tables without affecting the table's cluster, other clustered tables, or the cluster index. Drop a clustered table in the same manner as a non-clustered table-using the SQL command DROP TABLE. See page 2 - 8 for more information about individually dropping tables.

Note: When you drop a single clustered table from a cluster, each row of the table must be deleted from the cluster. To maximize efficiency if you intend to drop the entire cluster including all tables, use the DROP CLUSTER command with the INCLUDING TABLES option. You should only use the DROP TABLE command to drop an individual table from a cluster when the rest of the cluster is going to remain.

You can drop a cluster index without affecting the cluster or its clustered tables. However, you cannot use a clustered table if it does not have a cluster index. Cluster indexes are sometimes dropped as part of the procedure to rebuild a fragmented cluster index. See page 2 - 25 for more information about dropping indexes.

To drop a cluster that contains no tables, and its cluster index, if present, use the SQL command DROP CLUSTER. For example, the following statement drops the empty cluster named EMP_DEPT:

DROP CLUSTER emp_dept;

If the cluster contains one or more clustered tables and you intend to drop the tables as well, add the INCLUDING TABLES option of the DROP CLUSTER command, as in:

DROP CLUSTER emp_dept INCLUDING TABLES;

If you do not include the INCLUDING TABLES option, and the cluster contains tables, an error is returned.

If one or more tables in a cluster contain primary or unique keys that are referenced by FOREIGN KEY constraints of tables outside the cluster, you cannot drop the cluster unless you also drop the dependent FOREIGN KEY constraints. Use the CASCADE CONSTRAINTS option of the DROP CLUSTER command, as in:

DROP CLUSTER emp_dept INCLUDING TABLES CASCADE CONSTRAINTS;

An error is returned if the above option is not used in the appropriate situation.

 Privileges Required to Drop a Cluster

To drop a cluster, your schema must contain the cluster, or you must have the DROP ANY CLUSTER system privilege. You do not have to have any special privileges to drop a cluster that contains tables, even if the clustered tables are not owned by the owner of the cluster.

________________________________________

Managing Hash Clusters and Clustered Tables

The following sections explain how to create, alter, and drop hash clusters and clustered tables using SQL commands.

Creating Hash Clusters and Clustered Tables

A hash cluster is used to store individual tables or a group of clustered tables that are static and often queried by equality queries. Once you create a hash cluster, you can create tables. To create a hash cluster, use the SQL command CREATE CLUSTER. The following statement creates a cluster named TRIAL_CLUSTER that is used to store the TRIAL table, clustered by the TRIALNO column:

CREATE CLUSTER trial_cluster (trialno NUMBER(5,0))

   PCTUSED 80     PCTFREE 5

   SIZE 2K

   HASH IS trialno HASHKEYS 100000;

CREATE TABLE trial (

   trialno NUMBER(5) PRIMARY KEY,

   ...)

   CLUSTER trial_cluster (trialno);

Controlling Space Usage Within a Hash Cluster

When you create a hash cluster, it is important that you correctly choose the cluster key and set the HASH IS, SIZE, and HASHKEYS parameters to achieve the desired performance and space usage for the cluster. The following sections provide guidance, as well as examples of setting these parameters.

Choosing the Key     Choosing the correct cluster key is dependent on the most common types of queries issued against the clustered tables. For example, consider the EMP table in a hash cluster. If queries often select rows by employee number, the EMPNO column should be the cluster key; if queries often select rows by department number, the DEPTNO column should be the cluster key. For hash clusters that contain a single table, the cluster key is typically the entire primary key of the contained table. A hash cluster with a composite key must use ORACLE's internal hash function.

Setting HASH IS     Only specify the HASH IS parameter if the cluster key is a single column of the NUMBER datatype, and contains uniformly distributed integers. If the above conditions apply, you can distribute rows in the cluster such that each unique cluster key value hashes to a unique hash value (with no collisions). If the above conditions do not apply, you should use the internal hash function.

Dropping Hash Clusters

Drop a hash cluster using the SQL command DROP CLUSTER:

DROP CLUSTER emp_dept;

Drop a table in a hash cluster using the SQL command DROP TABLE. The implications of dropping hash clusters and tables in hash clusters are the same as for index clusters. See page 2 - 28 for more information about dropping clusters and the required privileges.

When to Use Hashing

Storing a table in a hash cluster is an alternative to storing the same table with an index. Hashing is useful in the following situations:

•	Most queries are equality queries on the cluster key. For example:

SELECT . . . WHERE cluster_key = . . . ;

In such cases, the cluster key in the equality condition is hashed, and the corresponding hash key is usually found with a single read. With an indexed table, the key value must first be found in the index (usually several reads), and then the row is read from the table (another read).

•	The table or tables in the hash cluster are primarily static in size such that you can determine the number of rows and amount of space required for the tables in the cluster. If tables in a hash cluster require more space than the initial allocation for the cluster, performance degradation can be substantial because overflow blocks are required.

•	A hash cluster with the HASH IS col, HASHKEYS n and SIZE m clauses is an ideal representation for an array (table) of n items (rows) where each item consists of m bytes of data. For example:

ARRAY X[100] OF NUMBER(8)

could be represented as:

CREATE CLUSTER c(subscript INTEGER)

   HASH IS subscript HASHKEYS 100 SIZE 10;

CREATE TABLE x(subscript NUMBER(2)), value NUMBER(8))

   CLUSTER c(subscript);

Alternatively, hashing is not advantageous in the following situations:

•	Most queries on the table retrieve rows over a range of cluster key values. For example, in full table scans, or queries such as:

SELECT . . . WHERE cluster_key < . . . ;

A hash function cannot be used to determine the location of specific hash keys; instead, the equivalent of a full table scan must be done to fetch the rows for the query. With an index, key values are ordered in the index, so cluster key values that satisfy the WHERE clause of a query can be found with relatively few I/Os.

•	A table is not static, but is continually growing. If a table grows without limit, the space required over the life of the table (thus, of its cluster) cannot be predetermined.

•	Applications frequently perform full-table scans on the table and the table is sparsely populated. A full-table scan in this situation takes longer under hashing.

•	You cannot afford to preallocate the space the hash cluster will eventually need.

In most cases, you should decide (based on the above information) whether to use hashing or indexing. If you use indexing, consider whether it is best to store a table individually or as part of a cluster; see page 2 - 26 for guidance.

If you decide to use hashing, a table can still have separate indexes on any columns, including the cluster key. For additional guidelines on the performance characteristics of hash clusters, see "How to Use Hashing" on page 5 - 8.

________________________________________

Miscellaneous Management Topics for Schema Objects

The following sections explain miscellaneous topics regarding the management of the various schema objects discussed in this chapter.

Creating Multiple Tables and Views in One Operation

You can create several tables and views and grant privileges in one operation using the SQL command CREATE SCHEMA. The CREATE SCHEMA command is useful if you want to guarantee the creation of several tables and views and grants in one operation; if an individual table or view creation fails or a grant fails, the entire statement is rolled back and none of the objects are created or the privileges granted. For example, the following statement creates two tables and a view that joins data from the two tables:

CREATE SCHEMA AUTHORIZATION scott

   CREATE VIEW sales_staff AS

      SELECT empno, ename, sal, comm

      FROM emp

      WHERE deptno = 30      WITH CHECK OPTION CONSTRAINT sales_staff_cnst

   CREATE TABLE emp (

      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)

   CREATE TABLE dept (

      deptno      NUMBER(3) PRIMARY KEY,

      dname       VARCHAR2(15),

      loc         VARCHAR2(25))

   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).

 Privileges Required to Create Multiple Schema Objects

To create schema objects, such as multiple tables, using the CREATE SCHEMA command, you must have the required privileges for any included operation.

Renaming Schema Objects

If necessary, you can rename some schema objects using two different methods: drop and recreate the object, or rename the object using the SQL command RENAME. If you drop an object and recreate it, all privilege grants for the object are lost when the object is dropped. Privileges must be regranted when the object is recreated. Alternatively, a table, view, sequence, or a private synonym of a table, view, or sequence can be renamed using the RENAME command. When using the RENAME command, grants made for the object are carried forward for the new name. For example, the following 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 recreate 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.

 Privileges Required to Rename an Object

To rename an object, you must be the owner of the object.

Name Resolution of Objects Referenced in SQL Statements

An object name takes the form:

[schema.]name[@database]

Some examples include:

emp

scott.emp

scott.emp@personnel

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 and 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 one 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.

Based on the context of an object name, ORACLE searches the appropriate namespace when resolving the name to an object. For example, in the statement:

DROP CLUSTER test

ORACLE knows to look up TEST in the cluster namespace.

Rather than supplying an object name directly, you can also refer to an object via 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.	Lookup the name in the table namespace.

2.	If the name resolves to an object that is not a synonym, no further work is needed.

3.	If the name resolves to a private synonym, replace the name with the definition of the synonym and return to step 1.

4.	If the name was originally qualified with a schema, return an error; otherwise, check if the name is a public synonym.

5.	If the name is not a public synonym, return an error; otherwise, replace the name with the definition 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 resolves the reference as is locally required (for example, resolving a synonym to a remote table's global object name). After the partially resolved statement is shipped to the remote database, the remote ORACLE completes the resolution of the object as above. See the ORACLE7 Server Concepts Manual for a complete description of name resolution in a distributed database.

________________________________________

Listing Information About Schema Objects

The data dictionary provides many views that provide information about the schema objects described in this chapter. The following is a summary of the views associated with schema objects:

•	ALL_OBJECTS, USER_OBJECTS

•	ALL_CATALOG, USER_CATALOG

•	ALL_TABLES, USER_TABLES

•	ALL_TAB_COLUMNS, USER_TAB_COLUMNS

•	ALL_TAB_COMMENTS, USER_TAB_COMMENTS

•	ALL_COL_COMMENTS, USER_COL_COMMENTS

•	ALL VIEWS, USER_VIEWS

•	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

The following sections provide examples of using some of the above views.

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;

The query above might return results similar to:

OBJECT_NAME               OBJECT_TYPE

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

EMP_DEPT                  CLUSTER

EMP                       TABLE

DEPT                      TABLE

EMP_DEPT_INDEX            INDEX

PUBLIC_EMP                SYNONYM

EMP_MGR                   VIEW

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 suffix. For example, the following query lists all of the default column values for the EMP and DEPT tables:

SELECT table_name, column_name, data_default

    FROM user_tab_columns

    WHERE table_name = 'DEPT' OR table_name = 'EMP';

Considering the example statements at the beginning of this section, a display similar to the one below is displayed:

TABLE_NAME  COLUMN_NAME     DATA_DEFAULT

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

DEPT        DEPTNO

DEPT        DNAME

DEPT        LOC             ('NEW YORK')

EMP         EMPNO

EMP         ENAME

EMP         JOB

EMP         MGR

EMP         HIREDATE        (sysdate)

EMP         SAL

EMP         COMM

EMP         DEPTNO

Notice that not all columns have a user-specified default. These columns assume NULL when rows that do not specify values for these columns are inserted.

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';

This query might return information similar to the following:

TABLE_OWNER                    TABLE_NAME

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

SCOTT                          DEPT

SCOTT                          EMP


CHAPTER 3. SELECTING A DATATYPE

This chapter discusses the ORACLE datatypes, their properties, and mapping to non-ORACLE datatypes. Topics discussed include:

•	the ORACLE datatypes: CHAR, VARCHAR2, NUMBER, DATE, LONG, RAW, and LONG RAW

•	ROWIDs and the ROWID datatype

•	the Trusted ORACLE MLSLABEL datatype

•	ANSI, SQL/DS, and DB2 datatypes

•	data conversions

________________________________________

ORACLE Datatypes

The following sections describe the ORACLE datatypes that can be used for column definitions.

Character Datatypes

The CHAR and VARCHAR2 datatypes are used to store alphanumeric data; any character can be stored in a column of these datatypes. Character data is stored in strings with byte values corresponding to the character encoding scheme (usually called a character set or code page) defined for the database when it was created, for example, 7-bit ASCII, EBCDIC Code Page 500, or Japan Extended UNIX. ORACLE supports both single-byte and multi-byte encoding schemes. See Appendix E for more information about National Language Support Features of ORACLE and support for different character encoding schemes.

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, 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, you must store these values in CHAR columns. For information on the comparison semantics for these datatypes, see the ORACLE7 Server SQL Language Reference Manual

 CHAR Datatype

The CHAR datatype is used to store fixed-length character strings. When you create a table with a CHAR column, specify a column length (in bytes, not characters) between 1 and 255 (default is 1). ORACLE then guarantees:

•	If a shorter value is given, the value is blank-padded to the fixed length.

•	If a value is too large, ORACLE returns an error.

ORACLE compares CHAR values using blank-padded comparison semantics. If two values have different lengths, ORACLE adds blanks to the shorter value, until the two values are the same length. Two values that differ only in the number of trailing blanks are considered equal.

VARCHAR2 Datatype

Use the VARCHAR2 datatype to store variable-length character strings. When you create a table with a VARCHAR2 column, specify a maximum column length (in bytes, not characters) between 1 and 2000. For each row, each value in the column is stored as a variable-length field. For example, assume a column is declared VARCHAR2 with a maximum size of 50 characters. If only 10 single-byte characters are given for the VARCHAR2 column value in a particular row, the column's length in the row's row piece only stores the 10 characters (10 bytes), not 50.

ORACLE compares VARCHAR2 values using non-padded comparison semantics. Two values are only considered equal if they have the same characters and are of equal length.

 VARCHAR Datatype

The VARCHAR datatype is currently synonymous with the VARCHAR2 datatype. However, in a future version of ORACLE, the VARCHAR datatype might be changed to use different comparison semantics. Therefore, you should use the VARCHAR2 datatype to store variable-length character strings.

 Column Lengths for Character Datatypes

The lengths of CHAR and VARCHAR2 columns are specified in bytes rather than characters, and are constrained as such. If the database character encoding scheme is single-byte, the number of bytes and the number of characters in a column is the same. If it is multi-byte, there generally is no such correspondence. A character might be comprised of one or more bytes depending upon the specific multi-byte encoding scheme, and whether shift-in/shift-out control codes are present. When using a multi-byte database character encoding scheme, consider carefully the space required for tables with character columns.

NUMBER Datatype

Use the NUMBER datatype to store zero, or positive or negative fixed or floating point numbers. Numbers using this datatype are guaranteed portable among different systems operating ORACLE, up to 38 decimal digits of precision. You can store positive and negative numbers of magnitude 1 x 10-130 to 9.99...x10125, as well as zero, in a NUMBER column.

For numeric columns you can specify the column as:

column_name NUMBER

or you can specify a precision (total number of digits) and scale (number of digits to right of decimal point)

column_name NUMBER (precision, scale)

If a precision is not specified, the column stores values as given. If no scale is specified, it is implied that the scale is zero. The scale can range from -84 to 127.

Although not required, specifying the precision and scale for numeric fields provides extra integrity checking on input. Table 3 - 1 shows examples of how data would be stored using different scale factors.

Notice that if a negative scale is specified, the actual data is rounded to the specified number of places to the left of the decimal point. For example, a specification of (7,-2) means to round to the nearest hundreds, as shown in Table 3 - 1.

Input Data	Specified As	Stored As

7,456,123.89	NUMBER	7456123.89

7,456,123.89	NUMBER (9)	7456124

7,456,123.89	NUMBER (9,2)	7456123.89

7,456,123.89	NUMBER (9,1)	7456123.9

7,456,123.89	NUMBER (6)	(not accepted, exceeds precision)

7,456,123.89	NUMBER (7, -2)	7456100

Table 3 - 1.  How Scale Factors Affect Numeric Data Storage

DATE Datatype

Use the DATE datatype to store point-in-time values (dates and times) in a table. The DATE datatype stores the year (including the century), the month, the day, the hours, the minutes, and the seconds. ORACLE can store dates ranging from January 1, 4712 BC through December 31, 4712 AD. Unless BC is specifically used, AD date entries are the default.

ORACLE uses its own internal format to store dates. Date data is stored in fixed-length fields of seven bytes each, corresponding to century, year, month, day, hour, minute, and second.

For input and output of dates, the standard ORACLE default date format is DD-MON-YY, as in:

'13-NOV-92'

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, as in:

TO_DATE ('November 13, 1992', 'MONTH DD, YYYY')

If the date format DD-MON-YY is used, YY indicates the year in the 20th century (such as 31-DEC-92 is December 31, 1992). If you want to indicate years in any century other than the 20th century, use a different format mask, as shown above.

Time is stored in 24-hour format-HH:MM:SS. By default, the time in a date field is 12:00:00 A.M. if no time portion is entered. In a time-only entry, the date portion defaults to the first 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:

INSERT INTO birthdays (bname, bday) VALUES

('ANNIE',TO_DATE('13-NOV-92 10:56 A.M.','DD-MON-YY HH:MI A.M.'));

To compare dates that have time data, use the SQL function TRUNC if you want to ignore the time component. Use the SQL function SYSDATE to return the system date and time. The FIXED_DATE parameter allows you to set SYSDATE to a constant; this can be useful for testing.

 Using Julian Dates

Julian dates allow continuous dating from a common reference. (The reference is 01 January 4712 years B.C., so current dates are somewhere in the 2.4 million range.) A Julian date is nominally a non-integer, the fractional part being a portion of a day. ORACLE uses a simplified approach that results in integer values. Julian dates can be calculated and interpreted differently; the calculation method used by ORACLE results in a seven-digit number for dates most often used, as in 2448355 for 08-APR-91.

Use the format mask "J" with date functions (TO_DATE or TO_CHAR, but not TO_NUMBER) to convert date data into Julian dates. For example, the following query returns all dates in Julian date format:

SELECT TO_CHAR (hiredate, 'J') FROM emp;

Use the TO_NUMBER function to use Julian dates in calculations. You can use the TO_DATE function to enter Julian dates:

INSERT INTO emp (hiredate) VALUES (TO_DATE(2448921, 'J'));

 Date Arithmetic

ORACLE date arithmetic takes into account the anomalies of the calendars used throughout history. For example, the switch from the Julian to the Gregorian calendar, 15 October 1582, eliminated the previous 10 days (05 October - 14 October). Additionally, the year 0 does not exist.

Missing dates can be entered into the database, but are ignored in date arithmetic and treated as the next date. For example, the next day after 04 October 1582 is 15 October 1582 and the day following 05 October 1582 is 16 Oct 1582.

Note: This discussion of date arithmetic may not apply to all countries' date standards (for example, Asia).

LONG Datatype

Columns defined as LONG can store variable-length character data containing up to 2 gigabytes of information. LONG columns have many of the characteristics of VARCHAR2 columns. The length of LONG values might be limited by the memory available on your computer.

 Uses of LONG Data

Columns defined with the LONG datatype are used in the data dictionary to store the text of view definitions. You can use columns defined as LONG in SELECT lists, SET clauses of UPDATE statements, and VALUES clauses of INSERT statements.

 Restrictions on LONG and LONG RAW Data

Though LONG (and LONG RAW) columns have many uses, there are some restrictions on their use:

•	Only one LONG column is allowed per table.

•	LONG columns cannot be indexed.

•	LONG columns cannot appear in integrity constraints.

•	LONG columns cannot be used in WHERE, GROUP BY, ORDER BY, or CONNECT BY clauses, or with the DISTINCT operator in SELECT statements.

•	LONG columns cannot be referenced by SQL functions (such as SUBSTR or INSTR).

•	LONG columns cannot be used in the SELECT list of a subquery or queries combined by set operators (UNION, UNION ALL, INTERSECT, or MINUS).

•	LONG columns cannot be used in SQL expressions.

•	LONG columns cannot be referenced when creating a table with a query (CREATE TABLE . . . AS SELECT . . .) or when inserting into a table (or view) with a query

(INSERT INTO . . . SELECT . . .).

•	A variable or argument of a PL/SQL program unit cannot be declared using the LONG datatype.

Suggestion: When you design tables containing LONG or LONG RAW data, you should place each LONG or LONG RAW column in a table separate from any other data associated with it, rather than storing the LONG or LONG RAW column and its associated data together in the same table. You can then relate the two tables with a referential integrity constraint. This design allows SQL statements that access only the associated data to avoid reading through LONG or LONG RAW data.

Example	To store information on magazine articles, including the texts of each article, create two tables:

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, first author, and journal and date of publication. The 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 first authors published in Nature magazine during July 1991, 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 first author, publication, and publication date, ORACLE would have to read through the text to perform this query.

RAW and LONG RAW Datatypes

Use the RAW and LONG RAW datatypes for data that is not to be interpreted (not to be converted when moving data between different systems) by ORACLE. These datatypes are intended for binary data and byte strings. For example, LONG RAW can be used to store graphics, sound, documents, and arrays of binary data; the interpretation is dependent on the use.

RAW is equivalent to VARCHAR2 and LONG RAW to LONG, except that the length of RAW cannot exceed 255 bytes, and there is no character set conversion done for RAW or LONG RAW data. CHAR, VARCHAR2, and LONG data is automatically converted from the database character set to the character set defined for the user session by the NLS_LANG parameter, where these are different.

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 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.

ROWIDs and the ROWID Datatype

Every row in a non-clustered table of an ORACLE database is assigned a unique ROWID that corresponds to the physical address of a row's row piece (initial row piece if the row is chained among multiple row pieces). In the case of clustered tables, rows in different tables that are in the same data block can have the same ROWID.

Each table in an ORACLE database internally has a pseudo-column named ROWID; this pseudo-column is not evident when listing the structure of a table by executing a SELECT * FROM . . . statement, or a DESCRIBE . . . statement using SQL*Plus. However, each row's address can be retrieved with a SQL query using the reserved word ROWID as a column name, as in:

SELECT ROWID, ename FROM emp;

ROWIDs use a binary representation of the physical address for each row selected. When queried using SQL*Plus or SQL*DBA, the binary representation is converted to a VARCHAR2/hexadecimal representation. The above query might return the following row information:

ROWID              ENAME

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

00000DD5.0000.0001 SMITH

00000DD5.0001.0001 ALLEN

00000DD5.0002.0001 WARD

As shown above, a ROWID's VARCHAR2/hexadecimal representation is divided into three pieces: block.row.file.

•	The data block that contains the row  (block DD5 in the example). Block numbers are relative to their data file, not tablespace. Therefore, two rows with identical block numbers could reside in two different data files of the same tablespace.

•	The row in the block that contains the row (rows 0, 1, 2 in the example). Row numbers of a given block always start with 0.

•	The data file that contains the row (file 1 in the example). The first data file of every database is always 1, and file numbers are distinct within a database.

A row's assigned ROWID remains unchanged unless the row is exported and imported (using the IMPORT and EXPORT utilities). When you delete a row from a table (and commit the encompassing transaction), the deleted row's associated ROWID can be assigned to a row inserted in a subsequent transaction.

You cannot set the value of the pseudo-column ROWID in INSERT or UPDATE statements. The ROWIDs in the pseudo-column ROWID are used internally by ORACLE for various operations (see the next section). Though you can reference ROWIDs in the pseudo-column ROWID like other table columns (used in SELECT lists and WHERE clauses), ROWIDs in this pseudo-column are not stored in the database, nor are they database data.

ROWIDs and Non-ORACLE Databases     To execute ORACLE database applications against non-ORACLE database servers, use SQL*Connect or the Oracle Open Gateway. In such cases, the binary format of ROWIDs varies according to the characteristics of the non-ORACLE system. Furthermore, no standard translation to VARCHAR2/hexadecimal format is available. Programs can still use the ROWID datatype; however, they must use a non-standard translation to hexadecimal format of length up to 256 bytes. Refer to the relevant manual for OCIs or Precompilers for further details on handling ROWIDs in conjunction with non-ORACLE systems.

 How ROWIDs Are Used

ROWIDs are used internally by ORACLE in the construction of indexes. Each key in an index is associated with a ROWID that points to the associated row's address for fast access. Some of the characteristics of ROWIDs include:

•	ROWIDs are the fastest means of accessing particular rows.

•	ROWIDs can be used to see how a table is organized.

•	ROWIDs are unique identifiers for rows in a given table.

Before using ROWIDs in DML statements, ROWIDs should be verified and guaranteed not to change; that is, the intended rows should be locked so they cannot be deleted. Attempting to retrieve a row using an invalid ROWID results in either no row being returned or error 1410, invalid ROWID.

You can also create tables with columns defined using the ROWID datatype; for example, you might define an exception table with a column of datatype ROWID to store the ROWIDs of rows in the database that violate integrity constraints. Such columns defined using the ROWID datatype behave like other table columns; that is, values can be updated, etc. All values in a column defined as datatype ROWID require six bytes to store pertinent column data.

 Examples of Using ROWIDs

Using some group functions with ROWID, you can see how data is internally stored in an ORACLE database. The function SUBSTR can be used to break the data in ROWID into its three components (file, block, and row). For example, the query:

SELECT ROWID, SUBSTR(ROWID,15,4) "FILE",

      SUBSTR(ROWID,1,8) "BLOCK",

      SUBSTR(ROWID,10,4) "ROW"

      FROM emp;

might return the following data:

ROWID               FILE  BLOCK     ROW

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

00000DD5.0000.0001  0001  00000DD5  0000

00000DD5.0001.0001  0001  00000DD5  0001

00000DD5.0002.0001  0001  00000DD5  0002

ROWIDs can be useful to reveal information about the physical storage of a table's data. For example, if you are interested in the physical location of a table's rows (for example, for table striping), the following query tells how many data files contain rows of a given table:

SELECT COUNT(DISTINCT(SUBSTR(ROWID,15,4))) "FILES" FROM tablename;

which might return:

   FILES

--------

       2

Summary of ORACLE Datatype Information

For quick reference, Table 3 - 2 summarizes the important information about each ORACLE datatype.

  Datatype	Description

CHAR (size)	FIxed-length character data of length size. Maximum

size is 255 bytes. Default size is 1 byte.

VARCHAR2 (size)	Variable-length charactger data. Maximum size is 2000

bytes. Default size is 1 byte.

Number (p, s)	Variable-length numeric data. The precision p (total

number of digits) can range from 1 to 38. The scale is s

(number of decimal places) can range from -84 to 127.

FLOAT (p)	A floating point number with binary precision p.

FLOAT with no precision is the same as FLOAT (126).

DATE	Fixed-length date and time data, ranging from January

1, 4712 BC to December 31, 4712 AD. Default format is

the value of the NLS_DATE_FORMAT or ALTER

SESSION parameter.

LONG	Variable-length character date up to 231 * 1 bytes - 1, or

2 gigabytes - 1 byte.

RAW (size)	Variable-length raw binary data. A maximum size must

be specified, up to 255.

LONG RAW	Variable-length raw binary data up to 231 * 1 bytes - 1,

or 2 gigabytes - 1 byte.

ROWID	Binary data representing row addresses.

MLSLABEL	Variable-length tag (2 - 5 bytes) that maps to a binary

operating system label. For use with Trusted ORACLE,

see page 3 - 11 for details.

Table 3 - 2.  Summary of ORACLE Datatype Information

________________________________________

The Trusted ORACLE MLSLABEL Datatype

Trusted ORACLE provides one new datatype:  the MLSLABEL datatype. You can declare columns of the MLSLABEL datatype in standard ORACLE, as well as Trusted ORACLE, for compatibility with Trusted ORACLE applications.

The MLSLABEL datatype is used to store the binary format of an operating system label. The maximum width of a column declared as MLSLABEL is 255 bytes.

Any labels that are valid on your operating system can be inserted into an MLSLABEL column. When you insert a label into an MLSLABEL column, Trusted ORACLE implicitly converts the data into the binary format of the label.

The ALL_LABELS Data Dictionary View

The ALL_LABELS data dictionary view lists all of the labels ever stored in the database, including the values of DBHIGH and DBLOW. Any label ever stored in an MLSLABEL column (including the ROWLABEL column) is automatically added to this view.

Note that this view does not necessarily contain all labels that are valid in the database, since any valid operating system label, in any valid format, is a valid label within Trusted ORACLE. Also note that this view may contain labels that are invalid within the database (if those labels were once used in the database, but are no longer valid).

Adding New Labels

If a label is not already in the ALL_LABELS view, and it is a valid operating system label, it is automatically added to the data dictionary as a valid label when you specify it in an INSERT or UPDATE statement.

For example, if TRULY_SENSITIVE:ALPHA, SENSITIVE, and UNCLASSIFIED are the only labels in the ALL_LABELS view, you can enter SENSITIVE:ALPHA into a column declared as MLSLABEL as long as SENSITIVE:ALPHA is a valid label in your operating system. Once inserted, this label automatically becomes a valid label in Trusted ORACLE and is displayed in the ALL_LABELS view.

________________________________________

The ROWLABEL Column

The ROWLABEL column is automatically appended to each Trusted ORACLE table at table creation. This column contains a label of the MLSLABEL datatype for every row in the table.

In OS MAC mode, given that a table can contain rows at one label only, the values in this column are always uniform within a table (and within a single database).

In DBMS MAC mode, the values in this column can range within a single table from DBHIGH to DBLOW (within any constraints defined for that table).

Retrieving Row Labels

The ROWLABEL column is not automatically returned as part of a query.  To retrieve the label of a row, you must explicitly select the ROWLABEL column.

For example, to retrieve the label of a row from a table or view, specify the ROWLABEL column in the SELECT statement:

SELECT rowlabel, ename FROM emp

   WHERE ename = 'JASUJA'

which returns:

ROWLABEL                           ENAME

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

SENSITIVE                          JASUJA

You can also specify the ROWLABEL pseudo-column in the WHERE clause of a SELECT statement.

SELECT rowlabel,ename FROM emp

    WHERE rowlabel = 'SENSITIVE'

which returns:

ROWLABEL                           ENAME

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

SENSITIVE                          JASUJA

SENSITIVE                          ASHER

 Retrieving All Labels From a Table

Note that when you select all columns from a table (SELECT *), the ROWLABEL column is not returned. You must explicitly specify that you want to retrieve the label in order to retrieve it. For example, to retrieve all columns, including the ROWLABEL column, from the DEPT table, enter:

SELECT rowlabel, dept.*

    FROM dept

This provides for compatibility with older applications (for example, ORACLE RDBMS Version 6) or those designed to run in single level and multilevel environments. However, the values for ROWLABEL are always utilized for MAC enforcement, and are always available in Trusted ORACLE for retrieval and display when specified.

 Retrieving Labels From Multiple Tables

To retrieve the label from more than one table or view, you must preface the ROWLABEL column with the table or view name. For example, to retrieve the ROWLABEL column from the EMP and DEPT tables wherever there is a match in department number, enter:

SELECT emp.rowlabel, dept.rowlabel

   FROM emp, dept

   WHERE emp.deptno = dept.deptno

If specifying the names of multiple tables becomes too lengthy, you can create synonyms for the table names within the query itself.

For example, the following query is identical to the query above:

SELECT emp.rowlabel, dept.rowlabel

    FROM emp e, dept d

   WHERE e.deptno = d.deptno

Modifying Row Labels

You can specify any valid operating system label in the ROWLABEL column, as described in"Adding New Labels" on page 3 - 12.

In OS MAC mode, you can perform inserts and updates to the ROWLABEL column under certain restrictions. In DBMS MAC mode, you can modify the ROWLABEL column if you have the appropriate MAC privileges

For detailed information on modifying the ROWLABEL column, see your Trusted ORACLE7 Server Administrator's Guide.

________________________________________

Displaying Your DBMS Label

Your DBMS label is the label at which you are connected to Trusted ORACLE. In OS MAC mode, this is always equivalent to the label of the database to which you are connected and always equivalent to your operating system session label. In DBMS MAC mode, this is the label with which you are connected to Trusted ORACLE; because privileged users can alter their DBMS labels, this does not necessarily equal the label of your operating system session.

You can display your DBMS label in any of the following ways:

•	The USERENV function

•	The SHOW command in SQL*DBA

 Displaying Your Label with the USERENV Function

To retrieve your DBMS label in any of the Oracle interactive tools (including SQL*Plus and SQL*DBA), use the LABEL parameter of the USERENV function.

For example, assume that you are logged in to the database at SENSITIVE. To determine your DBMS label, enter:

SELECT USERENV('label') FROM dual

which returns the following:

ROWLABEL

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

SENSITIVE

 Displaying Your Label with the SQL*DBA SHOW Command

To display your label in SQL*DBA, enter:

SQLDBA>	SHOW LABEL

which returns the following:

Label                    SENSITIVE

________________________________________

Altering Your DBMS Label

In DBMS MAC mode, you can alter your DBMS label with the SET LABEL parameter of the ALTER SESSION command. See your Trusted ORACLE7 Server Administrator's Guide for more information about using this command.

The ALTER SESSION SET LABEL command is valid in OS MAC mode; however, as you cannot set your DBMS label to any label other than that of the database to which you are connected, the command is superfluous.

________________________________________

ANSI/ISO, DB2, and SQL/DS Datatypes

In addition to ORACLE datatypes, you can define columns of tables in an ORACLE database using ANSI/ISO, DB2, and SQL/DS datatypes. However, ORACLE internally converts such datatypes to ORACLE datatypes.

ANSI SQL Datatype	ORACLE Datatype

CHARACTER (n), CHAR (n)	CHAR (n)

NUMERIC (p,s), DECIMAL (p,s), DEC (p,s)	NUMBER (p,s)

INTEGER, INT, SMALLINT	NUMBER (38)

FLOAT (p)	FLOAT (p)

REAL	FLOAT (63)

DOUBLE PRECISION	FLOAT (126)

CHARACTER VARYING(n), CHAR VARYING(n)	VARCHAR2 (n)

Table 3 - 3.  ANSI Datatype Conversions to ORACLE Datatypes.

DB2 or SQL/DS Datatype	ORACLE Datatype

CHARACTER (n)	CHAR (n)

VARCHAR (n)	VARCHAR2 (n)

LONG VARCHAR	LONG

DECIMAL (p,s)	NUMBER (p,s)

INTEGER, SMALLINT	NUMBER (38)

FLOAT (p)	FLOAT (p)

DATE	DATE

Table 3 - 4.  SQL/DS, DB2 Datatype Conversions to ORACLE Datatypes.

The IBM products SQL/DS, and DB2 datatypes TIME, TIMESTAMP, GRAPHIC, VARGRAPHIC, and LONG VARGRAPHIC have no corresponding ORACLE datatype, and cannot be used. The TIME and TIMESTAMP datatypes are subcomponents of the ORACLE datatype DATE.

The ANSI/ISO datatypes NUMERIC, DECIMAL, and DEC can specify only fixed-point numbers. For these datatypes, s defaults to 0.

________________________________________

Data Conversion

In some cases, ORACLE allows data of one datatype where it expects data of a different datatype. Generally, an expression cannot contain values with different datatypes. However, ORACLE can use the following functions to automatically convert data to the expected datatype:

•	TO_NUMBER()

•	TO_CHAR()

•	TO_DATE()

•	HEXTORAW()

•	RAWTOHEX()

•	ROWIDTOCHAR()

•	CHARTOROWID()

Implicit datatype conversions work according to the rules explained in the following two sections.

Note: In this discussion, CHAR is used to refer to the class of all character string datatypes.

If using Trusted ORACLE, see page 3 - 18 for additional information involving data conversions and the MLSLABEL and RAW MLSLABEL datatypes.

Rule 1: Assignments

For assignments, ORACLE can perform the following conversions automatically:

•	CHAR to NUMBER

•	CHAR to DATE

•	NUMBER to CHAR

•	DATE to CHAR

•	CHAR to RAW

•	RAW to CHAR

•	CHAR to ROWID

•	ROWID to CHAR

•	RAW to HEX

•	HEX to RAW

The assignment succeeds if ORACLE can convert the datatype of the value used in the assignment to that of the assignment's target. The four types of assignments are explained below.

For the examples in the following list, assume a package with a public variable declared as:

var1   CHAR(5);

and a table created with the following statement:

CREATE TABLE table1 (col1 NUMBER);

•	variable := expression

The datatype of expression must either be 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

•	INSERT INTO table VALUES (expression1, expression2, ...)

The datatypes of expression1, expression2, etc., must either be the same as, or convertible to, the datatypes of corresponding columns in table. For example, ORACLE automatically converts the data provided in the following INSERT statement for TABLE1 (see table definition above):

INSERT INTO table1 VALUES ('19');

•	UPDATE table SET column = expression

The datatype of expression must either be 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 SET col1 = '30';

•	SELECT column INTO variable FROM table

The datatype of column must either be 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 WHERE col1 = 30;

Rule 2: Expression Evaluation

For expression evaluation, ORACLE can automatically perform the same conversions as for assignments. An expression is converted to a type based on its context. For example, operands to arithmetic operators are converted to NUMBER and operands to string functions are converted to VARCHAR2.

Some common types of expressions follow:

•	Simple expressions, such as:

comm + '500'

•	Boolean expressions, such as:

bonus > sal / '10'

•	Function and procedure calls, such as:

MOD (counter, '2')

•	WHERE clause conditions, such as:

WHERE hiredate = TO_DATE('1993-01-01','yyyy-mm-dd')

•	WHERE clause conditions, such as:

WHERE rowid = '0DC5.C.1'

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 first evaluates expression using the conversions covered by Rule 2; expression can be as simple or complex as desired. If it succeeds, the evaluation of expression results in a single value and datatype. Then, ORACLE tries to assign this value to the assignment's target using Rule 1.

CHAR to NUMBER conversions only succeed if the character string represents a valid number. CHAR to DATE conversions only succeed if the character string satisfies the session default format, NLS_DATE_FORMAT.

________________________________________

Data Conversion for Trusted ORACLE

In Trusted ORACLE, labels are stored internally as compact binary structures. Trusted ORACLE provides two functions that allow you to convert a label from external (character or human readable) to internal (binary) format, and vice versa. These functions are described in the following sections.

The TO_CHAR Function

You can use the TO_CHAR function to convert a label from its binary to character representation, as follows:

TO_CHAR(label [,format])

where label is the binary representation of a label and format is a valid label format (see the following section, "Formatting Labels" on page 3 - 19 for more details about this parameter).

This function is useful because it allows you to retrieve a label in any supported format that suits your needs.

The TO_LABEL Function

You can use the TO_LABEL function to convert a label from a character string to its internal, binary representation.

To convert a label from character string to binary representation, enter:

TO_LABEL(string [,format])

where string is the character representation of a label and format is a valid label format (again, see the following section, "Formatting Labels," for more details about this parameter).

You must use the TO_LABEL function when converting a label from one external format to another. See "Formatting Labels" on page 3 - 19 for examples of how to use this function.

________________________________________

Formatting Labels

The default format in which Trusted ORACLE returns a label may not necessarily be the most appropriate format for a given display, report, or application. To accommodate different formatting needs, Trusted ORACLE provides the ability to:

•	Tailor the output of the TO_CHAR and TO_LABEL functions in a format that best suits your needs

•	Set a systemwide default label format (the MLS_LABEL_FORMAT initialization parameter)

•	Set a session default label format to override the systemwide default within a given application or session (the ALTER SESSION SET MLS_LABEL_FORMAT statement)

The following sections describe how to use these features in more detail.

Formatting Labels with the TO_CHAR and TO_LABEL Functions

Depending upon your operating system, a label can have several components:  sensitivity, integrity, information, and installation-defined. Both the sensitivity and integrity components consists of one classification and zero or more categories.

Using the format parameter of the TO_CHAR and TO_LABEL functions, you can format the classification and categories of each of these components in one of several ways:  numeric, short, or long. You can also specify whether you want the numeric, short, or long representation of a label to be displayed in the format used by the operating system on which Trusted ORACLE is running, and you can specify whether you want a label displayed in full operating system format. Note that not all operating systems support separate long and short formats.

 Setting the DBMS Label Format for Your Session

If you want to display labels in a format other than the systemwide default, you can alter the default format for your session with the SET MLS_LABEL_FORMAT parameter of the ALTER SESSION command. You need no special privileges to execute this command.

For example, assume that the systemwide default label format (set in the parameter file) is SEN; this displays the full sensitivity label in short format. However, you want the full sensitivity label to be displayed in numeric format just for your session or a portion of your session. To change the label format for your DBMS session to S, enter:

ALTER SESSION SET MLS_LABEL_FORMAT = 's'

All labels will then be displayed in this format for the duration of your session, or until you issue another ALTER SESSION SET MLS_LABEL_FORMAT command.

Note that altering the MLS_LABEL_FORMAT parameter not only changes the format in which labels are displayed for your session; it also changes the format in which you must enter labels. For example, after altering the MLS_LABEL_FORMAT parameter as described in the above example, you must enter labels in numeric format for the rest of your session.

Changing the MLS_LABEL_FORMAT parameter does not affect constraint enforcement.

For more information about different label formats, see your Trusted ORACLE7 Server Administrator's Guide.

________________________________________

Comparing Labels

In addition to formatting labels, you may need to perform comparison operations on labels. Trusted ORACLE lets you use standard comparison operators to:

•	Determine which of two or more labels dominates or is dominated by other labels

•	Determine if two or more labels are equal to each other

You can use the standard ORACLE comparison operators to compare labels in Trusted ORACLE.

________________________________________

Guidelines for Defining Labels

Labels and label formats vary from operating system to operating system. While your installation currently may not use more than one type of operating system, you should be aware of potential differences between labels and label formats in a distributed database configuration and for future porting considerations, particularly when writing applications that should be easily ported to other operating systems.

In order to promote portability between labels in databases from one operating system to another, you should consider the following guidelines when defining labels in your database.

Embedded Spaces and Punctuation

Be cautious when using embedded spaces and punctuation in labels, as not all operating systems can interpret them.

For example, a label of SENSITIVE:ALPHA/BETA may be correctly interpreted on one operating system, but not correctly interpreted by other operating systems.

Case Sensitivity

Use care when specifying labels using upper and lower case, as some operating systems are case sensitive and some are not. You should avoid defining labels that are distinguished only by case (for those operating systems that are not case sensitive); in addition, you should avoid comparing labels for an exact string match, including case (for those operating systems that are).

For example, one operating system may interpret Truly_Sensitive and TRULY_SENSITIVE as different labels; however, an operating system that is not case sensitive would interpret them as identical.

Label Components

Because not all operating systems support the integrity, information, and installation-defined portions of a label, you should use care when defining these in Trusted ORACLE or using them in applications.

Note that if you request a label component that is not supported by your operating system, Trusted ORACLE will return a null value for that component.

Numeric Format

You should avoid using '0' to represent either a classification or a category in numeric format, as some operating systems begin numbering with '0' and some with '1.'

Number of Classifications and Categories

Be aware that the number of classifications and categories supported by operating systems differs. Most operating systems support at least 16 hierarchical classifications; while most support 256, few support more. Most operating systems support 64 categories, but some support many more.


CHAPTER 4. PROCESSING SQL AND PL/SQL STATEMENTS

This chapter describes how ORACLE processes Structured Query Language (SQL) commands. Topics include:

•	the stages of executing each type of SQL statement

•	guidelines for controlling transactions

•	the use of cursors with SQL statements

•	explicit data locking

•	using array processing to improve performance

•	using PL/SQL to improve performance

Although some Oracle tools and applications simplify or mask the use of SQL, all database operations are performed using SQL. Any other data access method would circumvent the security built into ORACLE and potentially compromise data security and integrity.

________________________________________

SQL Statement Execution

Figure 4 - 1 outlines the stages commonly used to process and execute a SQL statement. In some cases, these steps might be executed in a slightly different order. For example, the DEFINE stage could occur just before the FETCH stage, depending on how your code is written.

The following sections describe each phase of SQL statement processing for each type of SQL statement. As you read this information, remember that for many Oracle tools, several of the phases are performed automatically. Most users need not be concerned with or aware of this level of detail. However, you might find this information useful when writing Oracle applications.

________________________________________

DML Statement Processing

The following section is a simplified look at what happens during the execution of a SQL statement. This example uses a DML statement (UPDATE). Queries (SELECTs) require additional steps as shown in Figure 4 - 1; refer to the section "Query Processing" on page 4 - 4 for more information.

Assume that you are using a Pro*C program to increase the salary for all employees in a department. Also assume that the program you are using has made a connection to ORACLE and that you are connected to the proper privileges to update the EMP table. You might embed the following SQL statement in your program:

EXEC SQL UPDATE emp SET sal = 1.10 * sal

   WHERE deptno = :dept_number;

DEPT_NUMBER is a program variable containing a value for department number. When the SQL statement is executed, the value of DEPT_NUMBER is used, as provided by the C language program.

The next four sections explain, in detail, what happens in each of the first four phases of DML statement processing. The same four phases are also necessary for each type of statement processing.

 Stage 1Create a Cursor

A cursor is created via a program interface call. The cursor is created independently of any SQL statement; it is created in expectation of any SQL statement. In most applications, cursor creation is automatic. However, in precompiler programs, cursor creation can occur implicitly, or explicitly by declaring a cursor. Refer to the section "The Use of Cursors" on page 4 - 10 for more information about cursors.

 Stage 2Parse the Statement

During parsing, the SQL statement is passed from the user process to ORACLE and a parsed representation of the SQL statement is loaded into a shared SQL area. Many errors can be caught during this phase of statement processing. Parsing is the process of:

•	translating a SQL statement, verifying it to be a valid statement

•	performing data dictionary lookups to check table and column definitions

•	acquiring parse locks on required objects so that their definitions do not change during the statement's parsing

•	checking privileges to access referenced schema objects

•	determining the execution plan to be used when executing

 the statement

•	loading it into a shared SQL area

•	for distributed statements, routing all or part of the statement to remote nodes that contain referenced data

A SQL statement is only parsed if a shared SQL area for an identical SQL statement does not exist in the shared pool. In this case, a new shared SQL area is allocated and the statement is parsed. For more information about shared SQL, refer to the section "Shared SQL" on page 4 - 9.

The parse phase includes processing requirements that only need to be done once no matter how many times the statement is executed. ORACLE translates each SQL statement only once, re-executing that parsed statement during subsequent references to the statement.

Although the parsing of a SQL statement validates that statement, parsing only identifies errors that can be found before statement execution. Thus, certain errors cannot be caught by parsing. For example, errors in data conversion or errors in data (such as an attempt to enter duplicate values in a primary key) and deadlocks are all errors or situations that can only be encountered and reported during the execution phase.

Query Processing

Queries are different from other types of SQL statements because they return data as results if they are successful. Whereas other statements return simply success or failure, a query can return one row or thousands of rows. The results of a query are always in tabular format, and the rows of the result are fetched (retrieved), either a row at a time or in groups.

Several issues relate only to query processing. Queries include not only explicit SELECT statements but also the implicit queries in other SQL statements. For example, each of the following statements requires a query as a part of its execution:

INSERT INTO table SELECT ...

UPDATE table SET x = y WHERE ...

DELETE FROM table WHERE ...

CREATE table AS SELECT ...

In particular, queries:

•	require read consistency

•	can use temporary segments for intermediate processing

•	can require the describe, define, and fetch phases of SQL statement processing

 Stage 3Describe Results

The describe phase is only necessary if the characteristics of a query's result are not known, for example, when a query is entered interactively by a user.

In this case, the describe phase is used to determine the characteristics (datatypes, lengths, and names) of a query's result.

 Stage 4Defining Output

In the define phase for queries, you specify the location, size, and datatype of variables defined to receive each fetched value. ORACLE performs datatype conversion if necessary.

 Stage 5Bind Any Variables

At this point, ORACLE knows the meaning of the SQL statement but still does not have enough information to execute the statement. ORACLE needs values for any variables listed in the statement; in the example, ORACLE needs a value for DEPT_NUMBER.

This process is called binding variables. A program must specify the location (memory address) where the value can be found. End users of applications might be unaware that they are specifying bind variables because the ORACLE utility might simply prompt them for a new value.

Because you specify the location (binding by reference), you need not rebind the variable before re-execution. You can change its value and ORACLE looks up the value on each execution, using the memory address.

Unless they are implied or defaulted, you must also specify a datatype and length for each value, in the event that ORACLE needs to perform datatype conversion. For more information about specifying a datatype and length for a value, refer to:

•	the Programmer's Guide to the ORACLE Precompilers when using a ORACLE precompiler (see "Dynamic SQL Method 4")

•	the Programmer's Guide to the ORACLE Call Interfaces (OCIs)

 Stage 6Execute the Statement

At this point, ORACLE has all necessary information and resources, so the statement is executed. If the statement is a query or an INSERT statement, no rows need to be locked because no data is being changed. If the statement is an UPDATE or DELETE statement, however, all rows that the statement affects are locked from use by other users of the database, until the next COMMIT, ROLLBACK or SAVEPOINT for the transaction. This ensures data integrity.

For some statements you can specify a number of executions to be performed. This is called array processing. Given n number of executions, the bind and define locations are assumed to be the beginning of an array of size n. For more details on array processing, see "Using Array Processing" on page 4 - 19.

 Stage 7Fetch Rows of a Query Result

In the fetch phase, rows are selected and ordered (if requested by the query), and each successive fetch retrieves another row of the result until the last row has been fetched.

________________________________________

DDL Statement Processing

The execution of DDL statements differs from the execution of DML statements and queries because the success of a DDL statement requires write access to the data dictionary. For these statements, the parse phase actually includes the parsing, data dictionary lookup, and execution.

Transaction management, session management, and system management SQL statements are processed using the parse and execute phases. To re-execute them, simply perform another execute.

________________________________________

Controlling Transactions

Usually the Oracle tool or application controls what constitutes a transaction; an end-user's primary concern is whether to commit or roll back a given transaction.

In general, only application designers using the programming interfaces to ORACLE are concerned with which types of actions should be grouped together as one transaction. Transactions must be defined properly so work is accomplished in logical units and data is kept consistent. A transaction should consist of all of the necessary parts for one logical unit of work, no more and no less. Data in all referenced tables should be in a consistent state before the transaction begins and after it ends. Transactions should consist of only the SQL statements that comprise one consistent change to the data.

A transfer of funds between two accounts (the transaction or logical unit of work), for example, should include the debit to one account (one SQL statement) and the credit to another account (one SQL statement). Both actions should either fail or succeed together as a unit of work; the credit should not be committed without the debit. Other non-related actions, such as a new deposit to one account, should not be included in the transfer of funds transaction.

In addition to determining which types of actions form a transaction, when you design an application you must also determine when it is useful to use the BEGIN_DISCRETE_TRANSACTION procedure to improve the performance of short, non-distributed transactions. Discrete transactions are described in Appendix A of this Guide.

Explicitly Assigning a Transaction to a Rollback Segment

Every transaction requires an associated rollback segment. Generally, a rollback segment is assigned automatically. You can, however, explicitly assign a transaction to an appropriate rollback segment using the SET TRANSACTION command with the USE ROLLBACK SEGMENT parameter. Transactions are explicitly assigned to rollback segments so that:

•	the anticipated amount of rollback information generated by a transaction can fit in the current extents of the assigned rollback segment

•	additional extents do not have to be dynamically allocated (and subsequently truncated) for rollback segments, which reduces overall system performance

To explicitly assign a transaction to a rollback segment, the rollback segment must be available (online) and the SET TRANSACTION USE ROLLBACK SEGMENT statement must be the first statement of the transaction. If a specified rollback segment is not available or a SET TRANSACTION USE ROLLBACK SEGMENT statement is not the first statement in a transaction, an error is returned.

For example, assume that you have committed the previous transaction and are about to begin a transaction that contains a significant amount of work (more than most transactions). In this case, you can assign the transaction to a large rollback segment:

SET TRANSACTION USE ROLLBACK SEGMENT large_rs1

After a transaction is committed, the next transaction is automatically assigned to a rollback segment. You should make the database administrator for your application aware of any transactions within your application that require large rollback segments.

Committing a Transaction

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 allows you to 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';

Also see Chapter 11 for additional information about committing in-doubt distributed transactions.

Rolling Back a Transaction

To roll back an entire transaction or a part of a transaction (i.e., to a savepoint), use the ROLLBACK command. For example, either of the following statements rolls back the entire current transaction:

ROLLBACK WORK;

ROLLBACK;

The WORK option of the ROLLBACK command has no function.

To roll back to a savepoint defined in the current transaction, the TO option of the ROLLBACK command must be used. For example, either of the following statements rolls back the current transaction to the savepoint named POINT1:

ROLLBACK TO SAVEPOINT point1;

ROLLBACK TO point1;

See Chapter 11 for additional information about rolling back in-doubt distributed transactions.

Defining a Transaction Savepoint

To define a savepoint in a transaction, use the SAVEPOINT command. The following statement creates the savepoint named ADD_EMP1 in the current transaction:

SAVEPOINT add_emp1;

If you create a second savepoint with the same identifier as an earlier savepoint, the earlier savepoint is erased. After a savepoint has been created, you can roll back to the savepoint.

There is no limit on the number of active savepoints per session. An active savepoint is one that has been specified since the last commit or rollback.

 An Example of COMMIT, SAVEPOINT, and ROLLBACK

The following series of SQL statements illustrates the use of COMMIT, SAVEPOINT, and ROLLBACK statements within a transaction:

SQL Statement	Results

SAVEPOINT A;	First savepoint of this transaction.

DELETE . . . ;	First DML statement of this transaction.

SAVEPOINT b;	Second savepoint of this transaction.

INSERT INTO . . . ;	Second DML statement of this transaction.

SAVEPOINT c;	Third savepoint of this transaction.

UPDATE . . . ;	Third DML statement of this transaction.

ROLLBACK TO c;	UPDATE statement is rolled back, savepoint C

remains defined.

ROLLBACK TO b;	INSERT staatement is rolled back, savepoint C

is lost, savepoint B remains defined.

ROLLBACK TO c;	Error-savepoint C no longer defined.

INSERT INTO . . . ;	New DML statement in this transaction.

COMMIT;	Commits all actions performed by the first

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

had been rolled back before the COMMIT.

Privileges Required for Transaction Management

No privileges are required to control your own transactions; any user can issue a COMMIT, ROLLBACK, or SAVEPOINT statement within their transaction.

________________________________________

Shared SQL

ORACLE automatically notices when two or more applications send identical SQL statements to the database. ORACLE identifies identical statements using the following steps:

1.	The text string of an issued statement is hashed. If the hash value is the same as a hash value for an existing SQL statement, ORACLE proceeds to Step 2.

2.	The text string of the issued statement, including case, blanks and comments, is compared to all existing SQL statements identified in Step 1. For example:

SELECT * FROM emp; is identical to SELECT * FROM emp;

SELECT * FROM emp; is not identical to SELECT * FROM Emp;

3.	The objects referenced in the issued statement are compared to the referenced objects of all existing statements identified in Step 2. For example, if two users have EMP tables, the statement

SELECT * FROM emp

is not considered identical because the statement references different tables for each user.

4.	The bind types of bind variables used in a SQL statement must match.

Notice that ORACLE does not have to parse a statement to determine if it is identical to another statement currently in the shared pool.

ORACLE considers SQL statements issued directly by users and applications as well as recursive SQL statements issued internally by a DDL statement.

If two identical statements are issued, the shared SQL area used to process the first instance of the statement is shared, or used for the processing of the subsequent instances of that same statement. Therefore, instead of having multiple shared SQL areas for identical SQL statements, only one shared SQL area exists for a unique statement. In summary, shared SQL areas are shared memory areas; any ORACLE process can use a shared SQL area. The use of shared SQL areas reduces memory usage on the database server, thereby increasing system throughput.

________________________________________

The Optimizer

When a SQL SELECT, UPDATE, INSERT, or DELETE statement is processed, ORACLE must access the data referenced by the statement. The optimizer portion of ORACLE is used to determine an efficient path to referenced data so that minimal I/O and processing time is required for statement execution. The optimizer formulates execution plans and chooses the most efficient plan before executing a statement. The optimizer uses one of two techniques to formulate execution plans for a SQL statement: a rule-based approach or a cost-based approach. Each of these approaches is described in Chapter 5 of this Guide.

________________________________________

The Use of Cursors

PL/SQL implicitly declares a cursor for all SQL data manipulation statements, including queries that return only one row. For queries that return more than one row, you can explicitly declare a cursor to process the rows individually.

A cursor is a handle to a specific private SQL area. In other words, a cursor can be thought of as a name for a specific private SQL area. Although most ORACLE users rely on the automatic cursor handling of the ORACLE utilities, the programmatic interfaces offer application designers more control over cursors. In application development, a cursor is a named resource available to a program, which can be specifically used for parsing SQL statements embedded within the application.

Declaring and Opening Cursors

There is no absolute limit to the total number of cursors one session can have open at one time, subject to two constraints:

•	Each cursor requires virtual memory, so a session's total number of cursors is limited by the memory available to that process.

•	A systemwide limit of cursors per session is set by the initialization parameter named OPEN_CURSORS found in the parameter file (such as, INIT.ORA). Parameters are described in the ORACLE7 Server Administrator's Guide.

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, you can make sure you can open that many simultaneously.

Using a Cursor to Re-execute Statements

After each stage of execution, the cursor retains enough information about the SQL statement to re-execute the statement without starting over, as long as no other SQL statement has been associated with that cursor. This is illustrated in Figure 4 - 1 on page 4 - 2.  Notice that the statement can be re-executed without including the first two stages.

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 bind or execute step, saving the repeated cost of opening cursors and parsing.

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:

•	The user program terminates its connection to the server.

•	If the user program is an OCI program, it explicitly closes any open cursor during the execution of that program. (However, when this program terminates, any cursors remaining open are implicitly closed.)

________________________________________

Explicit (Manual) Data Locking

ORACLE always performs necessary locking to ensure data concurrency, integrity, and statement-level read consistency. However, options are available to override the default locking mechanisms. Situations where it would be advantageous to override the default locking of ORACLE include:

•	Applications desire transaction-level read consistency or "repeatable reads"-transactions must query a consistent set of data for the duration of the transaction, knowing that the data has not been changed by any other transactions of the system. Transaction-level read consistency can be achieved only by using explicit locking, read-only transactions, or overriding default locking for the system.

•	Applications require that a transaction has 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.

The automatic locking mechanisms can be overridden at two different levels:

transaction level	Transactions including the following SQL statements override ORACLE's default locking: the LOCK TABLE command, the SELECT command including the FOR UPDATE clause, and the SET TRANSACTION command with the READ ONLY option. Locks acquired by these statements are released after the transaction commits or rolls back.

system level	An instance can be started with non-default locking by adjusting the initialization parameters SERIALIZABLE and ROW LOCKING.

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 the ORACLE7 Server Administrator's Guide for a discussion of parameters). The default value should be sufficient; however, if you are using additional manual locks, you may need to increase this value.

Warning: If you override the default locking of ORACLE at any level, be sure that the overriding locking procedures operate correctly; that is, be sure that data integrity is guaranteed, data concurrency is acceptable, and deadlocks are not possible or are appropriately handled.

Explicitly Acquiring Table Locks

A transaction explicitly acquires the specified table locks when a LOCK TABLE statement is executed. A LOCK TABLE statement manually overrides default locking. When a LOCK TABLE statement is issued on a view, the underlying base tables are locked. The following statement acquires exclusive table locks for the EMP and DEPT tables on behalf of the containing transaction:

LOCK TABLE emp, dept

   IN EXCLUSIVE MODE NOWAIT;

You can specify several tables or views to lock in the same mode; however, only a single lock mode can be specified per LOCK TABLE statement.

You can also indicate if you do or do not want to wait to acquire the lock. If you specify the NOWAIT option, 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 reattempt to lock the resource at a later time.  If NOWAIT is omitted, the transaction does not proceed until the requested table lock is acquired. If the wait for a table lock is excessive, you might want to cancel the lock operation and retry at a later time; you might prefer to code this logic into your applications.

Note: A distributed transaction waiting for a table lock can timeout waiting for the requested lock if the elapsed amount of time reaches the interval set by the initialization parameter DISTRIBUTED_LOCK_TIMEOUT. Refer to the section "Failures that Prevent the Access of Data" on page 11 - 6 for more information about this parameter.

The following paragraphs provide guidance on when it can be advantageous to acquire each type of table lock using the LOCK TABLE command.

ROW SHARE and ROW EXCLUSIVE	LOCK TABLE table IN ROW SHARE MODE;

LOCK TABLE table IN ROW EXCLUSIVE MODE;

Row share and row exclusive table locks offer the highest degree of concurrency. Conditions that possibly warrant the explicit acquisition of a row share or row exclusive table lock include:

•	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 modified later in your transaction.

SHARE	LOCK TABLE table IN SHARE MODE;

Share table locks are rather restrictive data locks. Conditions that could warrant the explicit acquisition of a share table lock include:

•	Your transaction only queries the table and requires a consistent set of the table's data for the duration of the transaction (that is, requires transaction-level read consistency for the locked table).

•	It is acceptable if other transactions attempting to update the locked table concurrently must wait until all transactions with the share table locks commit or roll back.

•	It is acceptable to allow other transactions to acquire concurrent share table locks on the same table, also allowing them the option of transaction-level read consistency.

Warning: 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 will be common. (Use share row exclusive or exclusive table locks instead.)

For example, assume that two tables, EMP and BUDGET, require a consistent set of data in a third table, DEPT. That is, 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 table in SHARE MODE, as shown in the following example. Because the DEPT table is not highly volatile, few, if any, users would need to update it while it was locked for the updates to EMP and BUDGET.

LOCK TABLE dept IN SHARE MODE

UPDATE EMP

SET sal = sal * 1.1

WHERE deptno IN (SELECT deptno FROM dept WHERE loc = 'DALLAS')

UPDATE budget

SET totsal = totsal * 1.1

WHERE deptno IN (SELECT deptno FROM dept WHERE loc = 'DALLAS')

COMMIT

SHARE ROW EXCLUSIVE	LOCK TABLE table IN SHARE ROW EXCLUSIVE MODE;

Conditions that warrant the explicit acquisition of a share row exclusive table lock include:

•	Your transaction requires both transaction-level read consistency for the specified table and the ability to update the locked table.

•	You are not concerned about explicit row locks being obtained (that is, via SELECT . . . FOR UPDATE) by other transactions, which may or may not make UPDATE and INSERT statements in the locking transaction wait to update the table (i.e., deadlocks may be observed).

•	You only want a single transaction to have the above behavior.

EXCLUSIVE	LOCK TABLE table IN EXCLUSIVE MODE;

Conditions that warrant the explicit acquisition of an exclusive table lock include:

•	Your transaction requires immediate update access to the locked table. Therefore, if your transaction holds an exclusive table lock, other transactions cannot lock specific rows in the locked table.

•	Your transaction also observes 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 to Explicitly Acquire Table Locks

You can automatically acquire any type of table lock on tables in your schema; however, 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, UPDATE) for the table.

________________________________________

Explicitly Acquiring Row Locks

You can override default locking with a SELECT statement that includes the FOR UPDATE clause. SELECT ... FOR UPDATE is used to acquire exclusive row locks for selected rows (as an UPDATE statement does) in anticipation of actually updating the selected rows.

You can use a SELECT ... FOR UPDATE statement to lock a row without actually changing it. For example, several triggers in Chapter 8 show how to implement referential integrity. In the EMP_DEPT_CHECK trigger (see page 8 - 20), the row that contains the referenced parent key value is locked to guarantee that it remains for the duration of the transaction; if the parent key is updated or deleted, referential integrity would be violated.

SELECT ... FOR UPDATE statements are often used by interactive programs that allow a user to modify fields of one or more specific rows (which might take some time); row locks on the rows are acquired so that only a single interactive program user is updating the rows at any given time.

If a SELECT ... FOR UPDATE statement is used to define a cursor, the rows in the return set are locked before the first fetch, when the cursor is opened; rows are not individually locked as they are fetched from the cursor. Locks are only released when the transaction that opened the cursor is committed or rolled back; locks are not released when a 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 conflicting row lock. Therefore, if a SELECT ... FOR UPDATE statement locks many rows in a table and the table experiences reasonable update activity, it would most likely improve performance if you instead acquired an exclusive table lock.

When acquiring row locks with SELECT ... FOR UPDATE, you can indicate if you do or do not want to wait to acquire the lock. If you specify the NOWAIT option, you only acquire the row lock if it is immediately possible. Otherwise, an error is returned to notify you that the lock is not possible at this time.  In this case, you can reattempt to lock the row at a later time.  If NOWAIT is omitted, the transaction does not proceed until the requested row lock is acquired. If the wait for a row lock is excessive, users might want to cancel the lock operation and retry at a later time; you might prefer to code such logic into applications.

A distributed transaction waiting for a row lock can timeout waiting for the requested lock if the elapsed amount of time reaches the interval set by the initialization parameter DISTRIBUTED_LOCK_TIMEOUT. Refer to the section "Failures That Prevent the Access of Data" on page 11 - 6 for more information about this parameter.

________________________________________

Read-Only Transactions

By default, the consistency model for ORACLE guarantees statement-level read consistency, but does not guarantee transaction-level read consistency (repeatable reads). If you want transaction-level read consistency and your transaction does not require updates, you can specify a read-only transaction. After indicating that your transaction is read-only, you can execute as many queries as you like against any database table, knowing that the results of each query in the read-only transaction are consistent with respect to a single point-in-time.

A read-only transaction does not acquire any additional data locks to provide transaction-level read consistency. The multi-version consistency model used for statement-level read consistency is used to provide transaction-level read consistency; all queries return information with respect to the SCN determined when the read-only transaction begins. As a result of no data locks being acquired, other transactions can query and update data being queried concurrently by a read-only transaction.

Changed data blocks queried by a read-only transaction are reconstructed using data from rollback segments. Therefore, long running read-only transactions sometimes receive an error to the effect that "snapshot too old." Create more, or larger, rollback segments to avoid this. Alternatively, you could issue long-running queries when online transaction processing is at a minimum, or you could obtain a shared lock on the table you were querying, prohibiting any other modifications during the transaction.

A read-only transaction is started with a SET TRANSACTION statement that includes the READ ONLY option. For example:

SET TRANSACTION READ ONLY;

The SET TRANSACTION statement must be the first 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 or 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).

________________________________________

Viewing and Monitoring Locks

ORACLE provides two facilities to display locking information for ongoing transactions within an instance:

SQL*DBA Monitors(Lock and Latch Monitors)	The Monitor feature of SQL*DBA provides two monitors for displaying lock information of an instance. Refer to the ORACLE7 Server Utilities User's Guide for complete information about the SQL*DBA monitors.

UTLLOCKT.SQL	The UTLLOCKT.SQL script displays a simple character lock wait-for graph in tree structured fashion. Using any ad hoc query tool (such as SQL*DBA, SQL*Plus), the script prints the sessions in the system that are waiting for locks and the corresponding blocking locks. The location of this script file is operating system dependent. (You must also run the script CATBLOCK.SQL before UTLLOCKT.SQL.)

________________________________________

The Initialization Parameters SERIALIZABLE and ROW_LOCKING

When an instance is started, two initialization parameters determine how the instance handles locking:  SERIALIZABLE and ROW_LOCKING. 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 who must run in ANSI/ISO compatible mode, or who want to use applications written to run with earlier versions of ORACLE. Only these sites should consider altering these parameters, as there is a significant performance degradation caused by using other than the defaults. For detailed explanations of these parameters, see the ORACLE7 Server Administrator's Guide.

The settings for these parameters should be changed only when an instance is shut down. If multiple instances are accessing a single database, all instances should use the same setting for these parameters.

Summary of Non-Default Locking Options

Two initialization parameters are available to change the way locking occurs at the system-level; as a result, there are three global settings other than the default. Table 4 - 1 summarizes the non-default settings and why you might choose to run your database system in a non-default way.

Case	Description	SERIALIZABLE	ROW_LOCKING

   1	Equivalent to Version 5 and earlier 	FALSE	INTENT

ORACLE releases (no concurrent in

serts, updates, or deletes in a table)

   2	ANSI compatible	TRUE	ALWAYS

   3	ANSI compatible, with table-level 	TRUE	INTENT

locking (no concurrent inserts, updates,

or deletes in a table)

Table 4 - 1.  Summary of Non-Default Locking Options

Table 4 - 2 illustrates the difference in locking behavior resulting from the three possible settings of the initialization parameters as shown in Table 4 - 1.

STATEMENT	CASE 1	CASE 2	CASE 3

STATEMENT	row	table	row	table	row	table

SELECT	-	-	-	S	-	S

INSERT	X	SRX	X	RX	X	SRX

UPDATE	X	SRX	X	SRX	X	SRX

DELETE	X	SRX	X	SRX	X	SRX

SELECT . . .FOR UPDATE	X	RS	X	S	X	S

LOCK TABLE . . . IN . .

  ROW SHARE MODE	RS	RS	RS	RS	RS	RS

  ROW EXCLUSIVE MODE	RX	RX	RX	RX	RX	RX

  SHARE MODE	S	S	S	S	S	S

  SHARE ROW EXCLUSIVE MODE	SRX	SRX	SRX	SRX	SRX	SRX

  EXCLUSIVE MODE	X	X	X	X	X	X

  DDL statements	-	X	-	X	-	X

Table 4 - 2.   Non-default Locking Behavior

________________________________________

Using Array Processing

Array processing can improve performance by reducing the number of calls from your application to ORACLE. Array processing allows your application to execute a single SQL statement many times with only a single call to ORACLE. This section tells you:

•	what array processing is

•	how array processing improves performance

•	how large to make your arrays

•	how to use array processing in your application

How Array Processing Improves Performance

Every SQL statement issued by an application is passed by the application to ORACLE. To pass a SQL statement to ORACLE, the application must make a function call. These function calls incur overhead that can reduce performance, especially if the application communicates with ORACLE over a network.

With array processing, the application can issue a SQL statement many times with a single call to ORACLE. For example, with array processing your application can make a single call to execute a SQL statement 100 times. Without array processing, your application must call ORACLE 100 times, once for each execution. By reducing the average overhead for each execution, array processing improves performance, especially in networked environments.

Choosing Array Sizes

The performance benefits of array processing depend upon the size of the array. By increasing the array size, you can further reduce the number of calls to ORACLE. However, increasing the array size beyond a certain point will yield negligible performance gains at the expense of great memory consumption. As a general guideline, use an array size of 100.

For example, suppose your application executes a SQL statement 10,000 times. Without array processing, the application must call ORACLE 10,000 times, once for each execution. However, with array processing and an array size of 100, the application must call ORACLE only 100 times, once for every 100 executions. In this case, increasing the array size to 100 reduces the number of calls by 9,900.

However, increasing the array size above 100 does not significantly improve performance. An array size of 1,000 reduces the number of calls to 10. This performance gain is relatively small compared to the gain from increasing the array size from 1 to 100. Increasing the array size to 100 also increases the amount of memory needed to hold the array.

Using Array Processing in Your Applications

Many ORACLE application tools can take advantage of array processing. Some of these tools, such as SQL*Forms, use array processing automatically. With other tools, you have some control over array processing. These tools include:

•	ORACLE Precompilers

•	ORACLE Call Interfaces (OCIs)

•	SQL*Plus

•	SQL*Loader

•	the Export and Import utilities

 Using Array Processing with the ORACLE Precompilers

With the ORACLE Precompilers, you can use array processing to execute an embedded SQL statement many times. Consider this embedded SQL statement in a Pro*C Precompiler program:

EXEC SQL INSERT INTO accounts (acc_no, acc_type, interest,

                               balance)

    VALUES (:acc_no, :acc_type, :interest, :balance);

If the variables ACC_NO, ACC_TYPE, INTEREST, and BALANCE are integers, the SQL statement is passed to ORACLE and executed once. ORACLE inserts a single row into the ACCOUNTS table. This row has column values specified by the variables.

However, if the variables ACC_NO, ACC_TYPE, INTEREST, and BALANCE are integer arrays of length 100, the SQL statement is passed to ORACLE and executed 100 times. ORACLE inserts 100 new rows into the ACCOUNTS table. In each row, each column has a value specified by of one of the elements of the corresponding array variable.

You can also use array processing in an ORACLE Precompiler program to fetch many rows with a single FETCH statement. For more information on array processing with the ORACLE Precompilers, see the Programmer's Guide to the ORACLE Precompilers or the Programmer's Guide to the Pro*Ada Precompiler.

 Using Array Processing with the ORACLE Call Interfaces (OCIs)

When using the ORACLE Call Interfaces (OCIs), you can implement array processing with these OCI calls:

OEXN	The OEXN call executes a SQL statement multiple times. One of the arguments of this call specifies the number of times the statement is to be executed.

OFEN	The OFEN call fetches multiple rows returned by a SQL query. One of the arguments of this call specifies the number of rows to be returned.

For more information on using array processing with the OCIs, see the Programmer's Guide to the ORACLE Call Interfaces or the Pro*Ada ORACLE Call Interface User's Guide.

 Using Array Processing with SQL*Plus

SQL*Plus uses array processing automatically to return many rows from the database at once. However, you can control the number of rows returned at a time.

The SQL*Plus system variable ARRAYSIZE determines how many rows are returned by a single call to ORACLE. The default value of ARRAYSIZE is 20. To see the current value of ARRAYSIZE, enter this SQL*Plus statement:

SQL> SHOW ARRAYSIZE

You can increase the number of rows returned by a single call by increasing the value of ARRAYSIZE. For example, to set the value of ARRAYSIZE to 100, enter this SQL*Plus statement:

SQL> SET ARRAYSIZE 100

ARRAYSIZE also determines the number of rows copied in a single batch by the SQL*Plus COPY command. For more information on SQL*Plus commands, see the SQL*Plus User's Guide and Reference.

 Using Array Processing with SQL*Loader

SQL*Loader uses array processing automatically to insert many rows into the database at once. However, you can control the number of rows inserted at a time.

The SQL*Loader command line argument ROWS determines how many rows are inserted at once. The default value for this argument is 64. To insert more rows at a time, specify a larger value for ROWS. For example, to insert arrays of 100 rows, you might invoke SQL*Loader with the statement:

SQLLOAD USERID=BAM/BIM, CONTROL=C1.CTL, DISCARD=D1.DIS, ROWS=100

For information on SQL*Loader, see the ORACLE7 Server Utilities User's Guide.

 Using Array Processing with the Import and Export Utilities

The Import and Export utilities use array processing automatically to read and write data to and from ORACLE. However, you can control the number of rows processed at a time.

If you are using Import or Export with the command-line method, you can control the array size by specifying the value of the BUFFER keyword. The BUFFER keyword determines the size in bytes of the buffer used to process data. The default value of this parameter depends upon your operating system.

To choose a value for BUFFER, determine the size of your rows in bytes. Then choose how many rows you want to process at once. Use the product of these values for the BUFFER value. For example, if you want to import rows that are about 4,096 bytes long, and you want to import 100 rows at a time, specify a BUFFER value of 409,600 bytes. You might invoke Import with this command:

IMP USERID=BAM/BIM IGNORE=Y FULL=N BUFFER=409600

If you are using Import or Export with the interactive method, the utility prompts you for the size of the buffer. The size you specify must be large enough to hold the largest row. If you specify a value of 0, the utility processes only one row at a time.

For more information on Import and Export, see the ORACLE7 Server Utilities User's Guide.

________________________________________

Using PL/SQL to Improve Performance

Anonymous blocks and stored procedures improve performance by reducing calls from your application to ORACLE. Reducing calls is especially helpful in networked environments where calls may incur a large overhead. PL/SQL reduces calls in these ways:

•	Your applications can pass multiple SQL statements to ORACLE at once.

•	Your SQL*Forms Version 3 or greater, or SQL*Menu Version 5 or greater applications can perform procedural operations without calling ORACLE.

Stored procedures further improve performance by eliminating parsing and automatically taking advantage of shared PL/SQL areas.

Packages further improve performance in these ways:

•	Storing related procedures and functions together in a package reduces the amount of I/O necessary to read them into memory.

•	Storing a procedure in a package allows you to redefine the procedure without causing ORACLE to recompile other procedures that call it. For more information on avoiding runtime recompilation, see the section "Avoiding Runtime Recompilation" beginning on page 9 - 2.

 The PL/SQL Engine in the ORACLE Server

Anonymous blocks and stored procedures allow applications to pass multiple SQL statements to ORACLE at once. A block containing multiple SQL statements can be passed to ORACLE in a single call. Without PL/SQL, applications must pass SQL statements one at a time, each with a separate call to ORACLE. Figure 4 - 2

illustrates how PL/SQL reduces network traffic and boosts performance.

 The PL/SQL Engine in ORACLE Application Tools

Anonymous blocks allow SQL*Forms and SQL*Menu applications to perform procedural functions that might otherwise require calls to ORACLE. Since a PL/SQL block can contain procedural statements, your application can use the PL/SQL engine incorporated into the ORACLE application tool to execute such statements.

For example, you should perform data calculations in your SQL*Forms applications by passing procedural statements to the PL/SQL engine, rather than by issuing SQL statements. SQL statements require calls to ORACLE, while the procedural statements can be processed by the PL/SQL engine in SQL*Forms itself. In this case, PL/SQL helps you avoid calling ORACLE altogether.

Using PL/SQL in Your Applications

You should use PL/SQL for parts of your applications that perform a great deal of database access. Follow these guidelines for using PL/SQL with specific ORACLE application tools to improve the performance of your applications:

ORACLE Precompilers	For database-intensive embedded SQL programs, pass multiple SQL statements to ORACLE by issuing anonymous blocks or calling stored procedures rather than by issuing multiple embedded SQL statements.

SQL*Plus	For small procedural tasks, issue anonymous blocks or call stored procedures from SQL*Plus rather than using SQL*Report or ORACLE Precompiler programs.

SQL*Forms	Replace multiple trigger steps in SQL*Forms applications with single trigger steps containing anonymous blocks.

For additional guidelines for developing applications using PL/SQL, see Chapter 7.


CHAPTER 5. TUNING SQL STATEMENTS

Tuning your SQL statements is an important part of getting the best possible performance from ORACLE. You should tune your SQL statements before your database administrator tunes ORACLE itself:

•	Even if you are not familiar with the internal workings of ORACLE, you can significantly improve performance by tuning your application based on your knowledge how ORACLE executes SQL statements.

•	If your SQL statements are not tuned well, they may not run well, even if ORACLE is tuned well.

This chapter tells you:

•	how to write SQL statements for best performance of new applications

•	how to optimize the performance of SQL statements in existing applications

This chapter assumes that you are familiar with the concept of an execution plan and how the ORACLE optimizer generates one. For this information, see Chapter 13 "The Optimizer" of the ORACLE7 Server Concepts Manual.

After you tune your SQL statements, your database administrator can begin tuning ORACLE as described in Chapter 20 "Understanding the Tuning Process" of the ORACLE7 Server Administrator's Guide.

________________________________________

How to Write New SQL Statements

If you are writing SQL statements in a new application, follow these steps to optimize your statements:

•	Create indexes that can be used by your statements.

•	Create clusters to optimize your join statements.

•	Create hash clusters that can be used by your statements.

•	Choose an optimization approach for your statements.

•	Use hints where appropriate in your statements.

•	Compare alternative syntaxes for your statements.

This section discusses each of these steps.

How to Use Indexes

This section makes recommendations about creating indexes and discusses these issues:

•	how to decide when to create indexes

•	how to choose which columns to index

•	how to use composite indexes

•	how to write statements to use indexes

Once you have decided to create an index, you can create it with the CREATE INDEX command. For more information on creating indexes, see Chapter 2 "Managing Schema Objects" of this Guide.

 When to Create Indexes

Indexes improve the performance of queries that select a small percentage of rows from a table. As a general guideline, you should create indexes on tables that are often queried for less than 2% or 4% of the table's rows. This guideline is based on these assumptions:

•	Rows with the same value for the column on which the query is based are uniformly distributed throughout the data blocks allocated to the table.

•	Rows in the table are randomly ordered with respect to the column on which the query is based.

•	Each data block allocated to the table contains at least 10 rows.

•	The table contains a relatively small number of columns.

•	Most queries on the table have relatively simple WHERE clauses.

If these assumptions do not describe the data in your table and the queries that access it, the percentage of the table's rows selected under which an index is helpful may increase to as much as 25%.

 How to Choose Columns to Index

Follow these guidelines for choosing columns to index:

•	Consider indexing columns that are used frequently in WHERE clauses.

•	Consider indexing columns that are used frequently to join tables in SQL statements. For more information on optimizing joins, see the section "How to Use Clusters" on page 5 - 7.

•	Only index columns with good selectivity. The selectivity of an index is the percentage of rows in a table having the same value for the indexed column. An index's selectivity is good if few rows have the same value. Note that ORACLE implicitly creates indexes on the columns of all unique and primary keys that you define with integrity constraints. These indexes are the most selective and the most effective in optimizing performance.

You can determine the selectivity of an index by dividing the number of rows in the table by the number of distinct indexed values. You can obtain these values using the ANALYZE command. A selectivity calculated in this manner should be interpreted as a percentage.

•	Do not index columns with few distinct values. Such columns usually have poor selectivity and, therefore, do not optimize performance unless the frequently selected column values appear less frequently than the other column values.

For example, consider a column containing equal numbers of the values 'YES' and 'NO'. Indexing this column would not normally improve performance. However, if the value 'YES' appears relatively infrequently and your application often queries for 'YES', then indexing the column may improve performance.

•	Do not index columns that are frequently modified. UPDATE statements that modify indexed columns and INSERT and DELETE statements that modify indexed tables take longer than if there were no index. Such SQL statements must modify data in indexes as well as data in tables.

•	Do not index columns that only appear in WHERE clauses with functions or operators. A WHERE clause that uses a function (other than MIN or MAX) or an operator with an indexed column does not make available the access path that uses the index.

•	Consider indexing foreign keys of referential integrity constraints in cases in which a large number of concurrent INSERT, UPDATE, and DELETE statements access the parent and child tables. Such an index allows ORACLE to modify data in the child table without locking the parent table.

When choosing whether to index a column, consider whether the performance gain for queries is worth the performance loss for INSERT, UPDATE, and DELETE statements and the use of the space required to store the index. You may want to experiment and compare the processing times of your SQL statements with and without indexes. You can measure processing time with the SQL trace facility. For information on the SQL trace facility, see Appendix B "Performance Diagnostic Tools" of this Guide.

 How to Choose Composite Indexes

A composite index is an index that is made up of more than one column. Composite indexes can provide additional advantages over single-column indexes:

better selectivity	Sometimes two or more columns, each with poor selectivity, can be combined in a composite index with good selectivity.

additional data storage	If all the columns selected by a query are in a composite index, ORACLE can return these values from the index without accessing the table.

A SQL statement can use an access path involving a composite index if the statement contains constructs that use a leading portion of the index. A leading portion of an index is a set of one or more columns that were specified first and consecutively in the list of columns in the CREATE INDEX statement that created the index. Consider this CREATE INDEX statement:

CREATE INDEX comp_ind

   ON tab1(x, y, z)

These combinations of columns are leading portions of the index:  X, XY, and XYZ. These combinations of columns are not leading portions of the index:  XZ, YZ, and Z.

Follow these guidelines for choosing columns for composite indexes:

•	Consider creating a composite index on columns that are frequently used together in WHERE clause conditions combined with AND operators, especially if their combined selectivity is better than the selectivity of either column individually.

•	If several queries select the same set of columns based on one or more column values, consider creating a composite index containing all of these columns.

Of course, consider the guidelines associated with the general performance advantages and tradeoffs of indexes described in the previous sections. Follow these guidelines for ordering columns in composite indexes:

•	Create the index so that the columns that are used in WHERE clauses make up a leading portion.

•	If some of the columns are used in WHERE clauses more frequently, be sure to create the index so that the more frequently selected columns make up a leading portion to allow the statements that use only these columns to use the index.

•	If all columns are used in WHERE clauses equally often, ordering these columns from most selective to least selective in the CREATE INDEX statement best improves query performance.

 How to Write Statements That Use Indexes

After you create an index, the optimizer cannot use an access path that uses the index simply because the index exists. The optimizer can only choose such an access path for a SQL statement if it contains a construct that makes the access path available. For information on access paths and the constructs that make them available, see Chapter 13 of the ORACLE7 Server Concepts Manual.

To be sure that a SQL statement can use an access path that uses an index, be sure the statement contains a construct that makes such an access path available. If you are using the cost-based approach, you should also generate statistics for the index. Once you have made the access path available for the statement, the optimizer may or may not choose to use the access path based on the availability of other access paths.

 How to Write Statements That Avoid Using Indexes

In some cases, you may want to prevent a SQL statement from using an access path that uses an existing index. You may want to do this if you know that the index is not very selective and that a full table scan would be more efficient. If the statement contains a construct that makes such an index access path available, you can force the optimizer to use a full table scan through one of these methods:

•	You can make the index access path unavailable by modifying the statement in a way that does not change its meaning. The following example illustrates this method.

•	You can use the FULL hint to force the optimizer to choose a full table scan instead of an index scan.

•	You can use the INDEX or AND_EQUAL hint to force the optimizer to use one index or set of indexes instead of another.

Since the behavior of the optimizer may change in future versions of ORACLE, relying on methods such as the first to choose access paths may not be a good long-range plan. Instead, use hints to suggest specific access paths to the optimizer. For information on hints, see the section "How to Use Hints" on page 5 - 12.

Example	Consider these queries that select rows from a table based on the value of a single column:

SELECT *

   FROM tab1

   WHERE col1 = 'A'

SELECT *

   FROM tab1

   WHERE col1 = 'B'

Assume that the values of the COL1 column are the letters A through Z. Assume also that the table has 1000 rows and that 75% of those rows have a COL1 value of 'A'. Each of the other letters appears in 1% of the rows.

Since the value 'A' appears in 75% of the tables rows, the first query is likely to be executed faster with a full table scan than with an index scan using an index on the COL1 column. Since the value 'B' appears in 1% of the rows, an index scan is likely to be faster than a full table scan for the second query. For these reasons, it is desirable to create an index to be used by the second query, but it is not desirable to use this index for the first query. However, the number of occurrences of each distinct column value is not available to the optimizer. The optimizer is likely to choose the same access path for both of these queries, despite the disparity in the percentage of the table's rows each returns.

For the best performance of these queries, create an index on TAB1.COL1 so that it can be used by the second query:

CREATE INDEX col1_ind

   ON tab1(col1)

Modify the WHERE clause of the first query so that it does not make available the access path that uses the COL1_IND index:

SELECT *

   FROM tab1

   WHERE col1 || '' = 'A'

This change prevents the query from using the access path provided by COL1_IND. Index access paths are not available if the WHERE clause performs an operation or function on the indexed column. For this reason, the optimizer must choose a full table scan for this query.

Note that this change to the WHERE clause does not change the result of the condition, so it does not cause the query to return a different set of rows. For a column containing number or date data, you can achieve the same goal by modifying the WHERE clause condition so that the column value is added to 0.

How to Use Clusters

Follow these guidelines for choosing when to cluster tables:

•	Consider clustering tables that are often accessed by your application in join statements.

•	Do not cluster tables if your application only joins them occasionally or modifies their common column values frequently. Modifying a row's cluster key value can take longer than modifying the value in an unclustered table because ORACLE may have to migrate the modified row to another block to maintain the cluster.

•	Do not cluster tables if your application often performs full table scans of only one of the tables. A full table scan of a clustered table can take longer than a full table scan of an unclustered table. ORACLE is likely to read more blocks since the tables are stored together.

•	Consider clustering master-detail tables if you often select a master record and then the corresponding detail records. Since the detail records are stored in the same data block(s) as the master record, they are likely to still be in memory when you select them, so ORACLE may perform less I/O.

•	Consider storing a detail table alone in a cluster if you often select many detail records of the same master. This measure improves the performance of queries that select detail records of the same master but does not decrease the performance of a full table scan on the master table.

•	Do not cluster tables if the data from all tables with the same cluster key value exceeds more than one or two ORACLE blocks. To access a row in a clustered table, ORACLE reads all blocks containing rows with that value. If these rows take up multiple blocks, accessing a single row could require more reads than accessing the same row in an unclustered table.

Consider the benefits and drawbacks of clusters with respect to the needs of your application. For example, you may decide that the performance gain for join statements outweighs the performance loss for statements that modify cluster key values. You may want to experiment and compare processing times with your tables both clustered and stored separately. To create a cluster, use the CREATE CLUSTER command. For more information on creating clusters, see Chapter 2 "Managing Schema Objects" of this Guide.

How to Use Hashing

Follow these guidelines for choosing when to use hash clusters:

•	Consider using hash clusters to store tables that are often accessed by SQL statements with WHERE clauses that contain equality conditions that use the same column or combination of columns. Designate this column or combination of columns as the cluster key.

•	Store a table in a hash cluster if you can determine how much space is required to hold all rows with a given cluster key value, including rows to be inserted immediately as well as rows to be inserted in the future.

•	Do not use hash clusters if space in your database is scarce and you cannot afford to allocate additional space for rows to be inserted in the future.

•	Do not use a hash cluster to store a constantly growing table if the process of occasionally creating a new, larger hash cluster to hold that table is impractical.

•	Do not store a table in a hash cluster if your application often performs full scans of the table and you feel you must allocate a great deal of extra space to the hash cluster in anticipation of the table growing a great deal in the future. Such full table scans must read all blocks allocated to the hash cluster, even though some blocks may contain few rows. Storing the table alone would reduce the number of blocks read by full table scans.

•	Do not store a table in a hash cluster if your application frequently modifies the cluster key values. Modifying a row's cluster key value can take longer than modifying the value in an unclustered table because ORACLE may have to migrate the modified row to another block to maintain the cluster.

•	Storing a single table in a hash cluster can be useful, regardless of whether the table is often joined with other tables, provided that hashing is appropriate for the table based on the previous points in this list.

Consider the benefits and drawbacks of hash clusters with respect to the needs of your application. You may want to experiment and compare processing times with a table both stored in a hash cluster and stored alone with an index. To create a hash cluster, use the CREATE CLUSTER command with the HASH and HASHKEYS parameters. For more information on creating hash clusters, see Chapter 2 "Managing Schema Objects" of this Guide.

 How to Determine How Many Hash Values to Use

When you create a hash cluster, you must use the HASHKEYS parameter of the CREATE CLUSTER statement to specify the number of hash values for the hash cluster. For best performance of hash scans, choose a HASHKEYS value that is at least as large as the number of cluster key values. Such a value reduces the chance of collisions, or multiple cluster key values resulting in the same hash value. Collisions force ORACLE to test the rows in each block for the correct cluster key value after performing a hash scan. Collisions reduce the performance of hash scans.

ORACLE always rounds up the HASHKEYS value that you specify to the nearest prime number to obtain the actual number of hash values. This rounding is designed to reduce collisions.

How to Choose an Optimization Approach

This section discusses:

•	when to use the cost-based approach

•	how to choose a goal for the cost-based approach

•	when and how to generate statistics for the cost-based approach

•	when to use the rule-based approach

 When to Use the Cost-Based Approach

In general, you should use the cost-based approach for all new applications. The cost-based approach generally chooses an execution plan that is as good as or better than the plan chosen by the rule-based approach, especially for large queries with multiple joins or multiple indexes. The cost-based approach also improves productivity by eliminating the need for you to tune your SQL statements yourself.

To enable cost-based optimization for a statement, collect statistics for the tables accessed by the statement and be sure the OPTIMIZER_MODE initialization parameter is set to its default value of CHOOSE.

You can also enable cost-based optimization in these ways:

•	To enable cost-based optimization for your session only, issue an ALTER SESSION statement with an OPTIMIZER_GOAL parameter value of ALL_ROWS or FIRST_ROWS.

•	To enable cost-based optimization for an individual SQL statement, use the ALL_ROWS or FIRST_ROWS hint. For information on hints, see the section "How to Use Hints" on page 5 - 12.

Generating Statistics     Since the cost-based approach relies on statistics, you should generate statistics for all tables, clusters, and indexes accessed by your SQL statements before using the cost-based approach. If the size and data distribution of these tables changes frequently, you should generate these statistics regularly to ensure that they accurately represent the data in the tables.

ORACLE can generate statistics using these techniques:

•	estimation based on random data sampling

•	exact computation

Use estimation, rather than computation, unless you think you need exact values:

•	Computation always provides exact values, but can take longer than estimation. The time necessary to compute statistics for a table is on the order of the time required to perform a full table scan of the table.

•	Estimation is often much faster than computation, especially for large tables, because estimation never reads more than 1064 rows from the table. The results are usually nearly exact.

When you generate statistics for a table, column, or index, if the data dictionary already contains statistics for the analyzed object, ORACLE updates the existing statistics with the new ones. ORACLE invalidates any currently parsed SQL statements that access any of the analyzed objects. When such a statement is next executed, the optimizer automatically chooses a new execution plan based on the new statistics. Distributed statements issued on remote databases that access the analyzed objects use the new statistics when they are next parsed.

Some statistics are always computed, regardless of whether you specify computation or estimation. If you choose estimation and the time saved by estimating a statistic is negligible, ORACLE computes the statistic.

You can generate statistics with the ANALYZE command.

Example	 This example generates statistics for the EMP table and its indexes:

ANALYZE TABLE emp

   ESTIMATE STATISTICS

Choosing a Goal for the Cost-Based Approach     The execution plan produced by the optimizer can vary depending upon the optimizer's goal. Optimizing for best throughput, or the minimum time to return all rows accessed by the statement, is more likely to result in a full table scan rather than an indexed scan or a sort-merge join rather than a nested loops join. Optimizing for best response time, or the minimum time to return the first row accessed by the statement, is more likely to result in an index scan or a nested loops join. For example, consider a join statement that can be executed with either a nested loops operation or a sort-merge operation. The sort-merge operation may return the entire query result faster, while the nested loops operation may return the first row faster. If the goal is best throughput, the optimizer is more likely to choose a sort-merge join. If the goal is best response time, the optimizer is more likely to choose a nested loops join.

Choose a goal for the optimizer based on the needs of your application:

•	For applications performed in batch, such as SQL*ReportWriter reports, optimize for best throughput. Throughput is usually more important in batch applications because the user initiating the application is only concerned with the time necessary for the application to complete. Response time is less important because the user does not examine the results of individual statements while the application is running.

•	For interactive applications, such as SQL*Forms applications or SQL*Plus queries, optimize for best response time. Response time is usually important in interactive applications because the interactive user is waiting to see the first row accessed by the statement.

By default, the cost-based approach optimizes for best throughput. You can change the goal of the cost-based approach in these ways:

•	To change the goal of the cost-based approach for all SQL statements in your session, issue an ALTER SESSION statement with the OPTIMIZER_GOAL parameter.

•	To specify the goal of the cost-based approach for an individual SQL statement, use the ALL_ROWS or FIRST_ROWS hint. For information on hints, see the section "How to Use Hints" on page 5 - 12.

Example	This statement changes the goal of the cost-based approach for your session to best response time:

ALTER SESSION

   SET OPTIMIZER_GOAL = FIRST_ROWS

 When to Use Rule-Based Optimization

If you have developed applications using a previous version of ORACLE and have carefully tuned your SQL statements based on the rules of the optimizer, you may want to continue using rule-based optimization when you upgrade these applications to ORACLE7. If you neither collect statistics nor add hints to your SQL statements, your statements will continue to use rule-based optimization. However, you should eventually migrate your existing applications to use the cost-based approach, because the rule-based approach will not be available in future versions of ORACLE.

You can enable cost-based optimization on a trial basis simply by collecting statistics. You can then return to rule-based optimization by deleting them or by setting either the value of the OPTIMIZER_MODE initialization parameter or the OPTIMIZER_GOAL parameter of the ALTER SESSION command to RULE. You can also use this value if you want to collect and examine statistics for your data without using the cost-based approach.

How to Use Hints

As an application designer, you may know information about your data that the optimizer cannot. For example, you may know that a certain index is more selective for certain queries than the optimizer can determine. Based on this information, you may be able to choose a more efficient execution plan than the optimizer can. In such a case, you can use hints to force the optimizer to use your chosen execution plan.

Hints are suggestions that you give the optimizer for optimizing a SQL statement. Hints allow you to make decisions usually made by the optimizer. You can use hints to specify:

•	the optimization approach for a SQL statement

•	the goal of the cost-based approach for a SQL statement

•	the access path for a table accessed by the statement

•	the join order for a join statement

•	a join operation in a join statement

Hints apply only to the optimization of the statement block in which they appear. A statement block is any one of the following statements or parts of statements:

•	a simple SELECT, UPDATE, or DELETE statement

•	a parent statement or subquery of a complex statement

•	a part of a compound query

For example, a compound query consisting of two component queries combined by the UNION operator has two statement blocks, one for each component query. For this reason, hints in this first component query apply only to its optimization, not to the optimization of the second component query.

You can send hints for a SQL statement to the optimizer by enclosing them in a comment within the statement. For more information on comments, see Chapter 2 "Elements of SQL"  of the ORACLE7 Server SQL Language Reference Manual.

A statement block can have only one comment containing hints. This comment can only follow the SELECT, UPDATE, or DELETE keyword. The syntax diagrams show the syntax for hints contained in both styles of comments that ORACLE supports within a statement block:

where:

DELETE SELECT UPDATE	is a DELETE, SELECT, or UPDATE keyword that begins a statement block. Comments containing hints can only appear after these keywords.

+	is a plus sign that causes ORACLE to interpret the comment as a list of hints. The plus sign must follow immediately after the comment delimiter (no space is permitted).

hint	is one of the hints discussed in this section. If the comment contains multiple hints, each pair of hints must be separated by at least one space.

text	is other commenting text that can be interspersed with the hints.

If you specify hints incorrectly, ORACLE ignores them, but does not return an error:

•	ORACLE ignores hints if the comment containing them does not follow a DELETE, SELECT, or UPDATE keyword.

•	ORACLE ignores hints containing syntax errors, but considers other correctly specified hints within the same comment.

•	ORACLE ignores combinations of conflicting hints, but considers other hints within the same comment.

ORACLE also ignores hints in all SQL statements in environments that use PL/SQL Version 1, such as SQL*Forms Version 3 triggers.

The optimizer only recognizes hints when using the cost-based approach. If you include any hint (except the RULE hint) in a statement block, the optimizer automatically uses the cost-based approach.

The following sections show the syntax of each hint.

 Hints for an Optimization Approaches and Goals

The hints described in this section allow you to choose between the cost-based and the rule-based optimization approaches and, with the cost-based approach, between the goals of best throughput and best response time. If a SQL statement contains a hint that specifies an optimization approach and goal, the optimizer uses the specified approach regardless of the presence or absence of statistics, the value of the OPTIMIZER_MODE initialization parameter, and the OPTIMIZER_GOAL parameter of the ALTER SESSION command.

ALL_ROWS	The ALL_ROWS hint explicitly chooses the cost-based approach to optimize a statement block with a goal of best throughput. For example, the optimizer uses the cost-based approach to optimize this statement for best throughput:

SELECT /*+ ALL_ROWS */ empno, ename, sal, job

   FROM emp

   WHERE empno = 7566

FIRST_ROWS	The FIRST_ROWS hint explicitly chooses the cost-based approach to optimize a statement block with a goal of best response time. This hint causes the optimizer to make these choices:

•	If an index scan is available, the optimizer always chooses it over a full table scan.

•	If an index scan is available, the optimizer always chooses a nested loops join over a sort-merge join whenever the associated table is the potential inner table of the nested loops.

•	If an index scan is made available by an ORDER BY clause, the optimizer always chooses it to avoid a sort operation.

For example, the optimizer uses the cost-based approach to optimize this statement for best response time:

SELECT /*+ FIRST_ROWS */ empno, ename, sal, job

   FROM emp

   WHERE empno = 7566

The optimizer ignores this hint in DELETE and UPDATE statement blocks and in SELECT statement blocks that contain any of this syntax:

•	set operators (UNION, INTERSECT, MINUS, UNION ALL)

•	GROUP BY clause

•	FOR UPDATE clause

•	group functions

•	DISTINCT operator

These statements cannot be optimized for best response time because ORACLE must retrieve all rows accessed by the statement before returning the first row. If you specify this hint in any of the these statements, the optimizer uses the cost-based approach and optimizes for best throughput.

If you specify either the ALL_ROWS or FIRST_ROWS hint in a SQL statement and the data dictionary contains no statistics about any of the tables accessed by the statement, the optimizer uses default statistical values such as allocated storage for such tables to estimate the missing statistics and subsequently to choose an execution plan. Since these estimates may not be as accurate as those generated by the ANALYZE command, you should use the ANALYZE command to generate statistics for all tables accessed by statements that use cost-based optimization.

If you specify hints for access paths or join operations along with either the ALL_ROWS or FIRST_ROWS hint, the optimizer ignores the ALL_ROWS or FIRST_ROWS hint and uses the cost-based approach to optimize the statement with the access paths and join operations specified by the hints.

RULE	The RULE hint explicitly chooses rule-based optimization for a statement block. This hint also causes the optimizer to ignore any other hints specified for the statement block. For example, the optimizer uses the rule-based approach for this statement:

SELECT                     --+ RULE

empno, ename, sal, job

   FROM emp

   WHERE empno = 7566

The RULE hint, along with the rule-bases approach, will not be available in future versions of ORACLE.

 Hints for Access Methods

Each hint described in this section suggests an access method for a table. Specifying one of these hints causes the optimizer to choose the specified access path only if the access path is available based on the existence of an index or cluster and the syntactic constructs of the SQL statement. For a discussion of access methods and a list of constructs and the access paths they make available, see Chapter 13 "The Optimizer" of the ORACLE7 Server Concepts Manual. If a hint specifies an unavailable access path, the optimizer ignores it.

You must specify the table to be accessed exactly as it appears in the statement. If the statement uses an alias for the table, you must use the alias, rather than the table name, in the hint. The name or alias must represent a table or a synonym for a table on your local database.

FULL	The FULL hint explicitly chooses a full table scan for the specified table. The syntax of the FULL hint is:

FULL(table)

where table specifies the name or alias of the table on which the full table scan is to be performed.

For example, ORACLE performs a full table scan on the ACCOUNTS table to execute this statement, even if there is an index on the ACCNO column that is made available by the condition in the WHERE clause:

SELECT /*+ FULL(a) Don't use the index on ACCNO */ accno, bal

   FROM accounts a

   WHERE accno = 7086854

Note that because the ACCOUNTS table has an alias A, the hint must refer to the table by its alias, rather than by its name.

ROWID	The ROWID hint explicitly chooses a table scan by ROWID for the specified table. The syntax of the ROWID hint is:

ROWID(table)

where table specifies the name or alias of the table on which the table access by ROWID is to be performed.

CLUSTER	 The CLUSTER hint explicitly chooses a cluster scan to access the specified table. The syntax of the CLUSTER hint is:

CLUSTER(table)

where table specifies the name or alias of the table to be accessed by a cluster scan.

HASH	The HASH hint explicitly chooses a hash scan to access the specified table. The syntax of the HASH hint is:

HASH(table)

where table specifies the name or alias of the table to be accessed by a hash scan.

INDEX	 The INDEX hint explicitly chooses an index scan for the specified table. The syntax of the INDEX hint is:

where:

table	specifies the name or alias of the table associated with the index to be scanned.

index	specifies an index on which an index scan is to be performed.

This hint may optionally specify one or more indexes:

•	If this hint specifies a single available index, the optimizer performs a scan on this index. The optimizer does not consider a full table scan or a scan on another index on the table.

•	If this hint specifies a list of available indexes, the optimizer considers the cost of a scan on each index in the list and then performs the index scan with the lowest cost. The optimizer may also choose to scan multiple indexes from this list and merge the results, if such an access path has the lowest cost. The optimizer does not consider a full table scan or a scan on an index not listed in the hint.

•	If this hint specifies no indexes, the optimizer considers the cost of a scan on each available index on the table and then performs the index scan with the lowest cost. The optimizer may also choose to scan multiple indexes and merge the results, if such an access path has the lowest cost. The optimizer does not consider a full table scan.

For example, consider this query that selects the name, height, and weight of all male patients in a hospital:

SELECT name, height, weight

   FROM patients

   WHERE sex = 'M'

Assume that there is an index on the SEX column and that this column contains the values M and F. If there are equal numbers of male and female patients in the hospital, the query returns a relatively large percentage of the table's rows and a full table scan is likely to be faster than an index scan. However, if a very small percentage of the hospital's patients are male, the query returns a relatively small percentage of the table's rows and an index scan is likely to be faster than a full table scan.

The number of occurrences of each distinct column value is not available to the optimizer. The cost-based approach assumes that each value has an equal probability of appearing in each row. For a column having only two distinct values, the optimizer assumes each value appears in 50% of the rows, so the cost-based approach is likely to choose a full table scan rather than an index scan.

If you know that the value in the WHERE clause of your query appears in a very small percentage of the rows, you can use the INDEX hint to force the optimizer to choose an index scan. In this statement, the INDEX hint explicitly chooses an index scan on the SEX_INDEX, the index on the SEX column:

SELECT /*+ INDEX(patients sex_index) Use SEX_INDEX, since there

                                are few male patients     */

name, height, weight

   FROM patients

   WHERE sex = 'M'

INDEX_ASC	The INDEX_ASC hint explicitly chooses an index scan for the specified table. If the statement uses an index range scan, ORACLE scans the index entries in ascending order of their indexed values. The syntax of the INDEX_ASC hint is:

Each parameter serves the same purpose as in the INDEX hint.

Because ORACLE's default behavior for a range scan is to scan index entries in ascending order of their indexed values, this hint does not currently specify anything more than the INDEX hint. However, since Oracle Corporation does not guarantee that the default behavior for an index range scan will remain the same in future versions of ORACLE, you may want to use the INDEX_ASC hint to specify ascending range scans explicitly, should the default behavior change.

INDEX_DESC	The INDEX_DESC hint explicitly chooses an index scan for the specified table. If the statement uses an index range scan, ORACLE scans the index entries in descending order of their indexed values. The syntax of the INDEX_DESC is:

Each parameter serves the same purpose as in the INDEX hint. This hint has no effect on SQL statements that access more than one table. Such statements always perform range scans in ascending order of the indexed values. For example, consider this table that contains the temperature readings of a tank of water holding marine life:

CREATE TABLE tank_readings

   (time         DATE    CONSTRAINT un_time UNIQUE,

    temperature  NUMBER )

Each of the table's rows stores a time and the temperature measured at that time.  A UNIQUE constraint on the TIME column ensures that the table does not contain more than one reading for the same time.

ORACLE enforces this constraint with an index on the TIME column. Consider this complex query that selects the most recent temperature reading taken as of a particular time T. The subquery returns either T or the latest time before T at which a temperature reading was taken. The parent query then finds the temperature taken at that time:

SELECT temperature

   FROM tank_readings

   WHERE time = (SELECT MAX(time)

      FROM tank_readings

         WHERE time <= TO_DATE(:t) )

The execution plan for this statement looks like this:

To execute this statement, ORACLE performs these operations:

•	Steps 4 and 3 execute the subquery:

•	Step 4 performs a range scan of the UN_TIME index to return all the TIME values less than or equal to T.

•	Step 3 chooses the greatest TIME value from Step 4 and returns it.

•	Steps 2 and 1 execute the parent query:

•	Step 2 performs a unique scan of the UN_TIME index based on the TIME value returned by Step 3 and returns the associated ROWID.

•	Step 1 accesses the TANK_READINGS table using the ROWID returned by Step 2 and returns the TEMPERATURE value.

In Step 4, ORACLE scans the TIME values in the index in ascending order beginning with the smallest. ORACLE stops scanning at the first TIME value greater than T and then returns all the values less than or equal to T to Step 3. Note that Step 3 needs only the greatest of these values. Using the INDEX_DESC hint, you can write an equivalent query that reads only one TIME value from the index:

SELECT /* INDEX_DESC(tank_readings un_time) */ temperature

   FROM tank_readings

   WHERE time <= TO_DATE(:t)

      AND ROWNUM = 1

The execution plan for this query looks like this:

To execute this statement, ORACLE performs these operations:

•	Step 3 performs a range scan of the UN_TIME index searching for TIME values less than or equal to T and returns their associated ROWIDs.

•	Step 2 accesses the TANK_READINGS table by the ROWIDs returned by Step 3.

•	Step 1 enforces the ROWNUM=1 condition by requesting only one row from Step 2.

Because of the INDEX_DESC hint, Step 3 scans the TIME values in the index in descending order beginning at T. The first TIME value scanned is either T (if the temperature was taken at T) or the greatest TIME value less than T. Since Step 1 requests only one row, Step 3 scans no more index entries after the first.

Since the default behavior is an ascending index scan, issuing this query without the INDEX_DESC hint would cause ORACLE to begin scanning at the earliest time in the table, rather than at the latest time less than or equal to T. Step 1 would then return the temperature at the earliest time. You must use this hint to make this query return the same temperature as the complex query described earlier in this section.

AND_EQUAL	The AND_EQUAL hint explicitly chooses an execution plan that uses an access path that merges the scans on several single-column indexes. The syntax of the AND_EQUAL hint is:

where:

table	specifies the name or alias of the table associated with the indexes to be merged.

index	specifies an index on which an index scan is to be performed. You must specify at least two indexes. You cannot specify more than five.

 HInts for Join Orders

The ORDERED hint suggests a join order.

ORDERED	The ORDERED hint causes ORACLE to join tables in the order in which they appear in the FROM clause. For example, this statement joins table TAB1 to table TAB2 and then joins the result to table TAB3:

SELECT /*+ ORDERED */ tab1.col1, tab2.col2, tab3.col3

   FROM tab1, tab2, tab3

   WHERE tab1.col1 = tab2.col1

      AND tab2.col1 = tab3.col1

If you omit the ORDERED hint from a SQL statement performing a join, the optimizer chooses the order in which to join the tables.

You may want to use the ORDERED hint to specify a join order if you know something about the number of rows selected from each table that the optimizer does not. Such information would allow you to choose an inner and outer table better than the optimizer could.

 Hints for Join Operations

Each hint described in this section suggests a join operation for a table. You must specify a table to be joined exactly as it appears in the statement. If the statement uses an alias for the table, you must use the alias rather than the table name in the hint. The name or alias must represent a table or a synonym for a table on your local database.

USE_NL	The USE_NL hint causes ORACLE to join each specified table to another row source with a nested loops join using the specified table as the inner table. The syntax of the USE_NL hint is:

where table is the name or alias of a table to be used as the inner table of a nested loops join.

For example, consider this statement that joins the ACCOUNTS and CUSTOMERS tables. Assume that these tables are not stored together in a cluster:

SELECT accounts.balance, customers.last_name, customers.first_name

   FROM accounts, customers

   WHERE accounts.custno = customers.custno

Since the default goal of the cost-based approach is to best throughput, the optimizer will choose either a nested loops operation or a sort-merge operation to join these tables, depending on which is likely to return all the rows selected by the query more quickly.

However, you may want to optimize the statement for best response time, or the minimal elapsed time necessary to return the first row selected by the query, rather than best throughput. If so, you can force the optimizer to choose a nested loops join by using the USE_NL hint. In this statement, the USE_NL hint explicitly chooses a nested loops join with the CUSTOMERS table as the inner table:

SELECT /*+ USE_NL(customers) Use Nested loops to get first row faster */

accounts.balance, customers.last_name, customers.first_name

   FROM accounts, customers

   WHERE accounts.custno = customers.custno

In many cases, a nested loops join returns the first row faster than a sort-merge join. A nested loops join can return the first row after reading the first selected row from one table and the first matching row from the other and combining them, while a sort-merge join cannot return the first row until after reading and sorting all selected rows of both tables and then combining the first rows of each sorted row source.

USE_MERGE	The USE_MERGE hint causes ORACLE to join each specified table with another row source with a sort-merge join. The syntax of the USE_MERGE hint is:

where table is a table to be joined to the row source resulting from joining the previous tables in the join order using a sort-merge join.

Considering Alternative Syntaxes

Because SQL is a flexible language, more than one SQL statement may meet the needs of your application. Although two SQL statements may produce the same result, ORACLE may process one faster than the other. You can use the results of the EXPLAIN PLAN statement to compare the execution plans and costs of the two statements and determine which is more efficient.

This example shows the execution plans for two SQL statements that perform the same function. Both statements return all the departments in the DEPT table that have no employees in the EMP table. Each statement searches the EMP table with a subquery. Assume there is an index, DEPTNO_INDEX, on the DEPTNO column of the EMP table.

This is the first statement and its execution plan:

SELECT dname, deptno

   FROM dept

   WHERE deptno NOT IN

      (SELECT deptno FROM emp)

Step 3 of the output indicates that ORACLE executes this statement by performing a full table scan of the EMP table despite the index on the DEPTNO column. This full table scan can be a time-consuming operation. ORACLE does not use the index because the subquery that searches the EMP table does not have a WHERE clause that makes the index available.

However, this SQL statement selects the same rows by accessing the index:

SELECT dname, deptno

   FROM dept

   WHERE NOT EXISTS

      (SELECT deptno

         FROM emp

WHERE dept.deptno = emp.deptno)

The WHERE clause of the subquery refers to the DEPTNO column of the EMP table, so the index DEPTNO_INDEX is used. The use of the index is reflected in Step 3 of the execution plan. The index range scan of DEPTNO_INDEX takes less time than the full scan of the EMP table in the first statement. Furthermore, the first query performs one full scan of the EMP table for every DEPTNO in the DEPT table. For these reasons, the second SQL statement is faster than the first.

If you have any statements in your applications that use the NOT IN operator as the first query in this example does, you should consider rewriting them so that they use the NOT EXISTS operator instead. This would allow such statements to use an index, if one exists.

________________________________________

How to Tune Existing SQL Statements

Tuning SQL statements in an existing application is a somewhat, but not altogether, different task from writing new statements. Although much of the required knowledge is the same, the process may be different. You must isolate particular statements in your application to tune. You can do that through these means:

•	Familiarize yourself with the application.

•	Isolate particular problem statements with the SQL trace facility.

You can then tune these statements individually using the recommendations for writing new SQL statements discussed in the previous section, including using indexes, clusters, hashing, and hints.

Know the Application

You must be familiar with the application, its SQL statements, and its data. If you did not design and develop the application, consult those who did. Find out what the application does:

•	what SQL statements the application uses

•	what data the application processes

•	what are the characteristics and distribution of the data

•	what operations the application performs on that data

Discuss performance with application users. Ask them to identify any parts of the application where they feel performance needs to be improved. Narrow these parts down to individual SQL statements, if possible.

Use the SQL Trace Facility

ORACLE provides several diagnostic tools for measuring performance. One of the tools especially helpful in tuning applications is the SQL trace facility. The SQL trace facility generates statistics for each SQL statement processed by ORACLE. These statistics reflect:

•	the number of times each SQL statement is parsed, executed, and fetched

•	the time necessary to process each SQL statement

•	the memory and disk access associated with each SQL statement

•	the number of rows each SQL statement processes

The SQL trace facility can also generate execution plans using the EXPLAIN PLAN command.

Run your application with the SQL trace facility enabled. From the resulting statistics, determine which SQL statements take the most time to process. Concentrate your tuning efforts on these statements.

For additional information on how to invoke the SQL trace facility and other performance diagnostic tools and analyze their output, see Appendix B "Performance Diagnostic Tools" of this Guide.

Tuning Individual SQL Statements

Keep in mind that you can explore alternative syntaxes for SQL statements without actually modifying your application. Simply use the EXPLAIN PLAN command with the alternative statement that you are considering and compare its execution plan and cost with that of the existing statement. You can find the cost of a SQL statement in the POSITION column of the first row generated by the EXPLAIN PLAN command. However, you must run the application to determine which statement can actually be executed more quickly.

If you create new indexes to tune statements, you can also use the EXPLAIN PLAN command to determine whether the optimizer will choose to use these indexes when the application is run. If you create new indexes to tune a statement that is currently parsed, ORACLE invalidates the statement. When the statement is next executed, the optimizer automatically chooses a new execution plan that could potentially use the new index. If you create new indexes on a remote database to tune a distributed statement, the optimizer considers these indexes when the statement is next parsed.

Also keep in mind that the means you use to tune one statement may affect the optimizer's choice of execution plans for others. For example, if you create an index to be used by one statement, the optimizer may choose to use that index for other statements in your application as well. For this reason, you should re-examine your application's performance and rerun the SQL trace facility after you have tuned those statements that you initially identified for tuning.


CHAPTER 6. MAINTAINING DATA INTEGRITY

This chapter explains how to enforce the business rules associated with your database and prevent the entry of invalid information into tables, using integrity constraints. Topics include:

•	the different types of integrity constraints

•	NOT NULL constraints

•	UNIQUE key constraints

•	PRIMARY KEY constraints

•	FOREIGN KEY (referential) constraints

•	CHECK constraints

•	how to define, enable, disable, and drop the different types of integrity constraints

See the Trusted ORACLE7 Server Administrator's Guide for additional information about defining, enabling, disabling, and dropping integrity constraints in Trusted ORACLE.

________________________________________

Using Integrity Constraints

You can define integrity constraints to enforce business rules on data in your tables. Once an integrity constraint is enabled, all data in the table must conform to the rule that it specifies. If you subsequently issue a SQL statement that modifies data in the table, ORACLE ensures that the resulting data satisfies the integrity constraint. Without integrity constraints, such business rules must be enforced programmatically by your application.

When to Use Integrity Constraints

Enforcing rules with integrity constraints is less costly than enforcing the equivalent rules by issuing SQL statements in your application. The semantics of integrity constraints are very clearly defined, so the internal operations that ORACLE performs to enforce them are optimized beneath the level of SQL statements in ORACLE. Since your applications use SQL, they cannot achieve this level of optimization.

Enforcing business rules through your application can be even more costly in a networked environment because the SQL statements must be transmitted over a network. In such cases, using integrity constraints can eliminate the performance overhead incurred by this transmission.

Example	To ensure that each employee in the EMP table works for a department that is listed in the DEPT table, first create a PRIMARY KEY constraint on the DEPTNO column of the DEPT table with this statement:

ALTER TABLE dept

   ADD PRIMARY KEY (deptno)

Then create a referential integrity constraint on the DEPTNO column of the EMP table that references the primary key of the DEPT table:

ALTER TABLE emp

   ADD FOREIGN KEY (deptno) REFERENCES dept(deptno)

If you subsequently add a new employee record to the table, ORACLE automatically ensures that its department number appears in the department table.

To enforce this rule without integrity constraints, your application must test each new employee record to ensure that its department number belongs to an existing department. This testing involves issuing a SELECT statement to query the DEPT table.

Taking Advantage of Integrity Constraints

For best performance, define and enable integrity constraints and develop your applications to rely on them, rather than on SQL statements in your applications, to enforce business rules.

However, in some cases, you might want to enforce business rules through your application as well as through integrity constraints. Enforcing a business rule in your application might provide faster feedback to the user than an integrity constraint. For example, if your application accepts 20 values from the user and then issues an INSERT statement containing these values, you might want your user to be notified immediately after entering a value that violates a business rule. Since integrity constraints are enforced only when a SQL statement is issued, an integrity constraint can only notify the user of a bad value after the user has entered all 20 values and the application has issued the INSERT statement. However, you can design your application to verify the integrity of each value as it is entered and notify the user immediately in the event of a bad value.

Using NOT NULL Integrity Constraints

By default, all columns can contain nulls. Only define NOT NULL constraints for columns of a table that absolutely require values at all times.

For example, in the EMP table, it might not be detrimental if an employee's manager or hire date were temporarily omitted. Also, some employees might not have a commission. Therefore, these three columns would not be good candidates for NOT NULL integrity constraints. However, it might not be permitted to have a row that does not have an employee name. Therefore, this column is a good candidate for the use of a NOT NULL integrity constraint.

NOT NULL constraints are often combined with other types of integrity constraints to further restrict the values that can exist in specific columns of a table. Use the combination of NOT NULL and UNIQUE key integrity constraints to force the input of values in the UNIQUE key; this combination of data integrity rules eliminates the possibility that any new row's data will ever attempt to conflict with an existing row's data. For more information about such combinations, see "Relationships Between Parent and Child Tables" on page 6 - 8.

Setting Default Column Values

Legal default values include any literal, or expression that does not refer to a column, LEVEL, ROWNUM, or PRIOR. Default values can include the expressions SYSDATE, USER, USERENV, and UID. The datatype of the default literal or expression must match or be convertible to the column datatype.

If you do not explicitly define a default value for a column, the default for the column is implicitly set to NULL.

 When to Use Default Values

Only assign default values to columns that contain a typical value. For example, in the DEPT table, if most departments are located at one site, the default value for the LOC column can be set to this value (such as NEW YORK).

Defaults are also useful when you use a view to make a subset of a table's columns visible. For example, you might allow users to insert rows into a table through a view. The view is defined to show all columns pertinent to end-user operations; however, the base table might also have a column named INSERTER, not included in the definition of the view, which logs the user that originally inserts each row of the table. The column named INSERTER can record the name of the user that inserts a row by defining the column with the USER function:

. . ., inserter VARCHAR2(30) DEFAULT USER, . . .

For another example of assigning a default column value, refer to the section "Creating Tables" on page 2 - 3.

Using UNIQUE Key Integrity Constraints

Choose unique keys carefully. In many situations, unique keys are incorrectly comprised of columns that should be part of the table's primary key (see the next section for more information about primary keys). When deciding whether to use a UNIQUE key constraint, use the rule that a UNIQUE key constraint is only required to prevent the duplication of the key values within the rows of the table. The data in a unique key is such that it cannot be duplicated in the table.

Do not confuse the concept of a unique key with that of a primary key. Primary keys are used to identify each row of the table uniquely. Therefore, unique keys should not have the purpose of identifying rows in the table.

Some examples of good unique keys include:

•	an employee's social security number (the primary key is the employee number)

•	a truck's license plate number (the primary key is the truck number)

•	a customer's phone number, consisting of the two columns AREA and PHONE (the primary key is the customer number)

•	a department's name and location (the primary key is the department number)

Choosing a Table's Primary Key

Each table can have one primary key. A primary key allows each row in a table to be uniquely identified and ensures that no duplicate rows exist. Use the following guidelines when selecting a primary key:

•	Choose a column whose data values are unique.

The purpose of a table's primary key is to uniquely identify each row of the table. Therefore, the column or set of columns in the primary key must contain unique values for each row.

•	Choose a column whose data values are never changed.

A primary key value is only used to identify a row in the table; primary key values should never contain any data that is used for any other purpose. Therefore, primary key values should rarely need to be changed.

•	Choose a column that does not contain any nulls.

A PRIMARY KEY constraint, by definition, does not allow the input of any row with 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. Numeric primary keys are easy to assign values using sequence numbers.

•	Avoid choosing composite primary keys.

Although composite primary keys are allowed, they rarely satisfy the previous recommendations. For example, composite primary key values are long and cannot be assigned by sequence numbers.

________________________________________

Using Referential Integrity Constraints

Whenever two tables are related by a common column (or set of columns), define a PRIMARY or UNIQUE key constraint on the column in the parent table, and define a FOREIGN KEY constraint on the column in the child table, to maintain the relationship between the two tables. Depending on this relationship, you may want to define additional integrity constraints including the foreign key, as listed in the section "Relationships Between Parent and Child Tables," on page 6 - 8.

Figure 6 - 3

shows a foreign key defined on the DEPTNO column of the EMP table. It guarantees that every value in this column must match a value in the primary key of the DEPT table (the DEPTNO column); therefore, no erroneous department numbers can exist in the DEPTNO column of the EMP table.

Foreign keys can be comprised of multiple columns. However, a composite foreign key must reference a composite primary or unique key of the exact same structure; that is, the same number of columns and datatypes. Because composite primary and unique keys are limited to 16 columns, a composite foreign key is also limited to 16 columns.

Nulls and Foreign Keys

By default (that is, in the absence of any NOT NULL or CHECK clauses), and in accordance with the ANSI/ISO standard, the FOREIGN KEY constraint enforces the "match none" rule for composite foreign keys. The "full" and "partial" rules can also be enforced by using CHECK and NOT NULL constraints, as follows:

•	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, define a CHECK constraint that allows only all nulls or all non-nulls in the composite foreign key as follows, assuming a composite key comprised of columns A, B, and C:

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))

•	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 outlined in Chapter 8.

Relationships Between Parent and Child Tables

Several relationships between parent and child tables can be determined by the other types of integrity constraints defined on the foreign key in the child table.

No Constraints on the Foreign Key     When no other constraints are defined on the foreign key, any number of rows in the child table can reference the same parent key value. This model allows nulls in the foreign key.

This model establishes a "one-to-many" relationship between the parent and foreign keys that allows undetermined values (nulls) in the foreign key. An example of such a relationship is shown in Figure 6 - 3 between EMP and DEPT; each department (parent key) has many employees (foreign key), and some employees might not be in a department (nulls in the foreign key).

NOT NULL Constraint on the Foreign Key     When nulls are not allowed in a foreign key, each row in the child table must explicitly reference a value in the parent key because nulls are not allowed in the foreign key. However, any number of rows in the child table can reference the same parent key value.

This model establishes a "one-to-many" relationship between the parent and foreign keys. However, each row in the child table must have a reference to a parent key value; the absence of a value (a null) in the foreign key is not allowed. The same example in the previous section can be used to illustrate such a relationship. However, in this case, employees must have a reference to a specific department.

UNIQUE Constraint on the Foreign Key     When a UNIQUE constraint is defined on the foreign key, one row in the child table can reference a parent key value. This model allows nulls in the foreign key.

This model establishes a "one-to-one" relationship between the parent and foreign keys that allows undetermined values (nulls) in the foreign key. For example, assume that the EMP table had a column named MEMBERNO, referring to an employee's membership number in the company's insurance plan. Also, a table named INSURANCE has a primary key named MEMBERNO, and other columns of the table keep respective information relating to an employee's insurance policy. The MEMBERNO in the EMP column should be both a foreign key and a unique key:

•	to enforce referential integrity rules between the EMP 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 defined 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. The same example listed in the last section applies in this model. However, no undetermined values (nulls) are allowed in the MEMBERNO column of the EMP table.

Multiple FOREIGN KEY Constraints

ORACLE allows a column to be referenced by multiple FOREIGN KEY constraints; effectively, there is no limit on the number of dependent keys. This situation might be present if a single column is part of two different composite foreign keys.

Concurrency Control, Indexes, and Foreign Keys

ORACLE maximizes the concurrency control of parent keys in relation to dependent foreign key values. You can control what concurrency mechanisms are used to maintain these relationships and, depending on the situation, this can be highly beneficial. The following sections explain the possible situations and give recommendations for each.

No Index on the Foreign Key     Figure 6 - 4 illustrates the locking mechanisms used by ORACLE when no index is defined on the foreign key and when new rows are inserted into the child table.

Notice that a share lock (reading allowed, writing not allowed) of the entire parent table is required until the transaction containing the INSERT statement for the child table is committed. Therefore, no INSERT, UPDATE, or DELETE statements can be issued on the parent table until this transaction is committed. Queries are allowed on the parent table.

This situation is tolerable if there is little update activity on the parent table.

Index on the Foreign Key     Figure 6 - 5 illustrates the locking mechanisms used by ORACLE when an index is defined on the foreign key, and new rows are inserted into the child table.

Notice that no locks of any kind are acquired on the parent table or any of its indexes. Therefore, any type of DML statement can be issued on the parent table, including inserts, updates, deletes, and queries.

This situation is preferable if there is any update or delete activity in the parent table while update activity is taking place in the child table.

________________________________________

Using CHECK Integrity Constraints

Use CHECK constraints when you need to enforce integrity rules that can be evaluated based on logical expressions. Never use CHECK constraints when any of the other types of integrity constraints can provide the necessary checking (see the section "CHECK and NOT NULL Integrity Constraints" on page 6 - 12.  Examples of appropriate CHECK constraints include:

•	a CHECK constraint on the SAL column of the EMP table so that no salary value is greater than 10000

•	a CHECK constraint on the LOC column of the DEPT table so that only the locations "BOSTON," "NEW YORK," and "DALLAS" are allowed

•	a CHECK constraint on the SAL and COMM columns to compare the SAL and COMM values of a row and prevent the COMM value from being greater than the SAL value

Restrictions on CHECK Constraints

A CHECK integrity constraint requires that a condition be true or unknown for every row of the table. If a statement causes the condition to evaluate to false, the statement is rolled back. The condition of a CHECK constraint has the following limitations:

•	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.

•	The condition cannot include the SYSDATE, UID, USER, or USERENV SQL functions.

•	The condition cannot contain the pseudo-columns LEVEL, PRIOR, or ROWNUM; see the ORACLE7 Server SQL Language Reference Manual for an explanation of these pseudo-columns.

Designing CHECK Constraints

When using CHECK constraints, consider the ANSI/ISO standard which states that a CHECK constraint is violated only if the condition evaluates to false; true and unknown values do not violate a check condition. Therefore, make sure that a CHECK constraint that you define actually enforces the rule you need enforced.

For example, consider the following CHECK constraint:

CHECK (sal > 0 OR comm >= 0)

At first glance, this rule may be interpreted as "do not allow a row in the EMP table unless the employee's salary is greater than 0 or the employee's commission is greater than or equal to 0." However, note that if a row is inserted with a null salary and a negative commission, the row does not violate the CHECK constraint because the entire check condition is evaluated as unknown. In this particular case, you can account for 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 conditions, review the truth tables for the logical operators AND and OR in the ORACLE7 Server SQL Language Reference Manual

Multiple CHECK Constraints

A single column can have multiple CHECK constraints that reference the column in its definition. There is no limit to the number of CHECK constraints that can be defined that reference a column.

CHECK and NOT NULL Integrity Constraints

According to the ANSI/ISO standard, a NOT NULL integrity constraint is an example of a CHECK integrity constraint, where the condition is:

CHECK (column_name IS NOT NULL)

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 define 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 can only 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))

________________________________________

Defining Integrity Constraints

Define an integrity constraint using the constraint clause of the SQL commands CREATE TABLE or ALTER TABLE. The next two sections describe how to use these commands to define integrity constraints.

There are additional considerations if you are using Trusted ORACLE; see the Trusted ORACLE7 Server Administrator's Guide for more information.

Defining Integrity Constraints in the CREATE TABLE Command

The following examples of CREATE TABLE statements show the definition of several integrity constraints:

CREATE TABLE dept (

   deptno  NUMBER(3) PRIMARY KEY,

   dname   VARCHAR2(15),

   loc     VARCHAR2(15),

            CONSTRAINT dname_ukey UNIQUE (dname, loc),

            CONSTRAINT loc_check1

                CHECK (loc IN ('NEW YORK', 'BOSTON', 'CHICAGO')));

CREATE TABLE emp (

   empno    NUMBER(5) PRIMARY KEY,

   ename    VARCHAR2(15) NOT NULL,

   job      VARCHAR2(10),

   mgr      NUMBER(5) CONSTRAINT mgr_fkey

                 REFERENCES emp,

   hiredate DATE,

   sal      NUMBER(7,2),

   comm     NUMBER(5,2),

   deptno   NUMBER(3) NOT NULL

               CONSTRAINT dept_fkey

               REFERENCES dept ON DELETE CASCADE);

Defining Integrity Constraints in the ALTER TABLE Command

You can also define integrity constraints using the constraint clause of the ALTER TABLE command. For example, the following examples of ALTER TABLE statements show the definition of several integrity constraints:

ALTER TABLE dept

   ADD PRIMARY KEY (deptno);

 ALTER TABLE emp

   ADD CONSTRAINT dept_fkey FOREIGN KEY (deptno) REFERENCES dept

   MODIFY (ename VARCHAR2(15) NOT NULL);

 Restrictions with the ALTER TABLE Command

Because data is likely to be in the table at the time an ALTER TABLE statement is issued, there are several restrictions to be aware of. Table 6 - 1 lists each type of constraint and the associated restrictions with the ALTER TABLE command.

Type of	Added to Existing 	Added with New

Constraint	Columns of the Table	Columns to the Table

NOT NULL	Cannot be defined if any 	Cannot be defined if the

row contains a null value 	table contains any rows

for this column1

UNIQUE	Cannot be defined if dupli	Always OK

cate values exist in the

key1

PRIMARY 	Cannot be defined if dupli	Cannot be defined if the

KEY	cate or null values exist in 	table contains any rows

the key1

FOREIGN 	Cannot be defined if the 	Always OK

KEY	foreign key has values that

do not reference a parent

key value1

CHECK	Cannot be defined if the 	Always OK

volumn has values that do

not comply with the check

condition1

Table 6 - 1.  Restrictions for Defining Integrity Constraints with the ALTER

TABLE Command.

1  Assumes DISABLE clause not included in statement.

If you attempt to define a constraint with an ALTER TABLE statement and violate one of these restrictions, the statement is rolled back and an informative error is returned explaining the violation.

Privileges Required to Create Integrity Constraints

The creator of a 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 table (that is, the ALTER object privilege for the table or the ALTER ANY TABLE system privilege) with the constraint. Additionally, UNIQUE key and PRIMARY KEY integrity constraints require that the owner of the table have either a quota for the tablespace that contains the associated index or the UNLIMITED TABLESPACE system privilege. FOREIGN KEY integrity constraints also require some additional privileges; see "Privileges Required for FOREIGN KEY Integrity Constraints" on page 6 - 21 for specific information.

Naming Integrity Constraints

Assign names to NOT NULL, UNIQUE KEY, PRIMARY KEY, FOREIGN KEY, and CHECK constraints using the CONSTRAINT option of the constraint clause. This name must be unique with respect to other constraints that you own. If you do not specify a constraint name, one is assigned by ORACLE.

See the previous examples of the CREATE TABLE and ALTER TABLE statements for examples of the CONSTRAINT option of the Constraint clause. Note that the name of each constraint is included with other information about the constraint in the data dictionary. Refer to the section "Listing Integrity Constraint Definitions" on page 6 - 22 for examples of data dictionary views.

Enabling and Disabling Constraints Upon Definition

By default, whenever an integrity constraint is defined in a CREATE or ALTER TABLE statement, the constraint is automatically enabled (enforced) by ORACLE unless it is specifically created in a disabled state using the DISABLE clause. Refer to the section "Enabling and Disabling Integrity Constraints" on page 6 - 15 for more information about important issues for enabling and disabling constraints.

Defining UNIQUE Key, PRIMARY KEY, and FOREIGN KEY Integrity Constraints

When defining UNIQUE key, PRIMARY KEY, and FOREIGN KEY integrity constraints, you should be aware of several important issues and prerequisites. For more information about defining and managing FOREIGN KEY constraints, see "Managing FOREIGN KEY Integrity Constraints," on page 6 - 20 UNIQUE key and PRIMARY KEY constraints are usually enabled by the database administrator; see the ORACLE7 Server Administrator's Guide for more information.

________________________________________

Enabling and Disabling Integrity Constraints

This section explains the mechanisms and procedures for manually enabling and disabling integrity constraints.

enabled constraint	When a constraint is enabled, the rule defined by the constraint is enforced on the data values in the columns that define the constraint. The definition of the constraint is stored in the data dictionary.

disabled constraint	When a constraint is disabled, the rule defined by the constraint is not enforced on the data values in the columns included in the constraint; however, the definition of the constraint is retained in the data dictionary.

In summary, an integrity constraint can be thought of as a statement about the data in a database. This statement is always true when the constraint is enabled; however, the statement may or may not be true when the constraint is disabled because data in violation of the integrity constraint can be in the database.

Why Enable or Disable Constraints?

To enforce the rules defined by integrity constraints, the constraints should always be enabled; however, in certain situations, it is desirable to disable the integrity constraints of a table temporarily for performance reasons. For example:

•	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 everyone's employee number by adding 1000 to the existing number)

•	when importing or exporting one table at a time

In all three cases, integrity constraints may be temporarily turned off to improve the performance of the operation.

Integrity Constraint Violations

If a row of a table does not adhere to an integrity constraint, this row is said to be in violation of the constraint and is known as an exception to the constraint. If any exceptions exist, the constraint cannot be enabled. The rows that violate the constraint must be either updated or deleted in order for the constraint to be enabled.

Exceptions for a specific integrity constraint can be identified while attempting to enable the constraint. This procedure is discussed in the section "Exception Reporting" on page 6 - 18.

Enabling and Disabling Integrity Constraints Upon Definition

When you define an integrity constraint in a CREATE TABLE or ALTER TABLE statement, you can enable the constraint by including the ENABLE clause in its definition or disable it by including the DISABLE clause in its definition. If neither the ENABLE nor the DISABLE clause is included in a constraint's definition, ORACLE automatically enables the constraint.

 Enabling Constraints

The following CREATE TABLE and ALTER TABLE statements both define and enable integrity constraints:

CREATE TABLE emp (

   empno NUMBER(5) PRIMARY KEY,   . . . );

 ALTER TABLE emp

   ADD PRIMARY KEY (empno);

An ALTER TABLE statement that defines and attempts to enable an integrity constraint may fail because rows of the table may violate the integrity constraint. In this case, the statement is rolled back and the constraint definition is not stored and not enabled. Refer to the section "Exception Reporting" on page 6 - 18 for more information about rows that violate integrity constraints.

 Disabling Constraints

The following CREATE TABLE and ALTER TABLE statements both define and disable integrity constraints:

CREATE TABLE emp (

   empno NUMBER(5) PRIMARY KEY DISABLE,   . . . );

 ALTER TABLE emp

   ADD PRIMARY KEY (empno) DISABLE;

An ALTER TABLE statement that defines and disables an integrity constraints never fails. The definition of the constraint is always allowed because its rule is not enforced.

Enabling and Disabling Defined Integrity Constraints

Use the ALTER TABLE command to:

•	Enable a disabled constraint, using the ENABLE clause.

•	Disable an enabled constraint, using the DISABLE clause.

 Enabling Disabled Constraints

The following statements are examples of statements that enable disabled integrity constraints:

ALTER TABLE dept

   ENABLE CONSTRAINT dname_ukey;

ALTER TABLE dept

   ENABLE PRIMARY KEY,

   ENABLE UNIQUE (dname, loc);

An ALTER TABLE statement that attempts to enable an integrity constraint fails when the rows of the table violate the integrity constraint. In this case, the statement is rolled back and the constraint is not enabled. Refer to the section "Exception Reporting" on page 6 - 18 for more information about rows that violate integrity constraints.

 Disabling Enabled Constraints

The following statements are examples of statements that disable enabled integrity constraints:

ALTER TABLE dept

   DISABLE CONSTRAINT dname_ukey;

ALTER TABLE dept

   DISABLE PRIMARY KEY,

   DISABLE UNIQUE (dname, loc);

 Tip:Using the Data Dictionary For Reference

The example statements in the previous sections require that you know some information about a constraint to enable or disable it. For example, the first statement of each section requires that you know the constraint's name, while the second statement of each section requires that you know the unique key's column list. If you do not know such information, you can query one of the data dictionary views defined for constraints; for more information about these views, see "Listing Integrity Constraint Definitions" on page 6 - 22 and Appendix D.

Enabling and Disabling UNIQUE Key, PRIMARY KEY, and FOREIGN KEY Integrity Constraints

When enabling or disabling UNIQUE key, PRIMARY KEY, and FOREIGN KEY integrity constraints, you should be aware of several important issues and prerequisites. For more information about enabling, disabling, and managing FOREIGN KEY constraints see "Managing FOREIGN KEY Integrity Constraints" on page 6 - 20. UNIQUE key and PRIMARY KEY constraints are usually managed by the database administrator; see the ORACLE7 Server Administrator's Guide for more information.

Exception Reporting

If no exceptions are present when you issue a CREATE TABLE. . . ENABLE . . . or ALTER TABLE . . . ENABLE . . . statement the integrity constraint is enabled and all subsequent DML statements are subject to the enabled integrity constraints.

If exceptions exist when you enable a constraint, an error is returned and the integrity constraint remains disabled. When a statement is not successfully executed because integrity constraint exceptions exist, the statement is rolled back. If exceptions exist, you cannot enable the constraint until all exceptions to the constraint are either updated or deleted.

To determine which rows violate the integrity constraint, include the EXCEPTIONS option in the ENABLE clause of a CREATE TABLE or ALTER TABLE statement. The EXCEPTIONS option places the ROWID, table owner, table name, and constraint name of all exception rows into a specified table. For example, the following statement attempts to enable the primary key of the DEPT table; if exceptions exist, information is inserted into a table named EXCEPTIONS:

ALTER TABLE dept ENABLE PRIMARY KEY EXCEPTIONS INTO exceptions;

Create SQLan appropriate exceptions report table to accept information from the EXCEPTIONS option of the ENABLE clause. Create an exception table by submitting the script UTLEXCPT.SQL. The script creates a tabled named EXCEPTIONS. You can create additional exceptions tables with different names by modifying and resubmitting the script.

If duplicate primary key values exist in the DEPT table and the name of the PRIMARY KEY constraint on DEPT is SYS_C00301, the following rows might be placed in the table EXCEPTIONS by the previous statement:

SELECT * FROM exceptions;

 ROWID               OWNER  TABLE_NAME   CONSTRAINT

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

000003A5.000C.0001     SCOTT   DEPT      SYS_C00301

000003A5.000D.0001     SCOTT   DEPT        SYS_C00301

A more informative query would be to join the rows in an exception report table and the master table to list the actual rows that violate a specific constraint. For example:

SELECT deptno, dname, loc FROM dept, exceptions

   WHERE exceptions.constraint = 'SYS_C00301'

   AND dept.rowid = exceptions.row_id;

 DEPTNO     DNAME          LOC

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

        10 ACCOUNTING     NEW YORK

        10 RESEARCH       DALLAS

Rows that violate a constraint must be either updated or deleted from the table that contains the constraint. If updating exceptions, you must change the value that violates the constraint to a value consistent with the constraint or a null (if allowed). After updating or deleting a row in the master table, delete the corresponding rows for the exception in the exception report table to avoid confusion with later exception reports. The statements that update the master table and the exception report table should be in the same transaction to ensure transaction consistency.

For example, to correct the exceptions in the previous examples, the following transaction might be issued:

UPDATE dept SET deptno = 20 WHERE dname = 'RESEARCH';

DELETE FROM exceptions WHERE constraint = 'SYS_C00301';

COMMIT;

When managing exceptions, the goal is to eliminate all exceptions in your exception report table. After all exceptions have been eliminated, you must re-enable the constraint; the constraint is not automatically enabled after the exceptions are handled.

While you are correcting current exceptions for a table with the constraint disabled, other users can issue statements creating new exceptions.

________________________________________

Altering Integrity Constraints

Once defined, integrity constraints cannot be altered. If you must alter the action defined by a given integrity constraint, drop the existing constraint and create a replacement.

________________________________________

Dropping Integrity Constraints

Drop an integrity constraint if the rule that it enforces is no longer true or if the constraint is no longer needed. Drop an integrity constraint using the ALTER TABLE command and the DROP clause. For example, the following statements drop integrity constraints:

ALTER TABLE dept

   DROP UNIQUE (dname, loc);

ALTER TABLE emp

   DROP PRIMARY KEY,

   DROP CONSTRAINT dept_fkey;

Dropping UNIQUE Key, PRIMARY KEY, and FOREIGN KEY Integrity Constraints

When dropping UNIQUE key, PRIMARY KEY, and FOREIGN KEY integrity constraints, you should be aware of several important issues and prerequisites.   For more information about dropping FOREIGN KEY constraints see "Managing FOREIGN KEY Integrity Constraints" on page 6 - 20. UNIQUE key and PRIMARY KEY constraints are usually managed by the database administrator; see the ORACLE7 Server Administrator's Guide for more information.

________________________________________

Managing FOREIGN KEY Integrity Constraints

General information about defining, enabling, disabling, and dropping all types of integrity constraints is given in the previous sections. The following section supplements this information, focusing specifically on issues regarding FOREIGN KEY integrity constraints.

Defining FOREIGN KEY Integrity Constraints

The following topics are of interest when defining FOREIGN KEY integrity constraints.

 Matching of Datatypes

When defining referential integrity constraints, the corresponding column names of the dependent and referenced tables do not need to match. However, they must be of the same datatype.

 Composite Foreign Keys

Because foreign keys reference primary and unique keys of the parent table, and PRIMARY KEY and UNIQUE key constraints are enforced using indexes, composite foreign keys are limited to 16 columns.

 Implied Referencing of a Primary Key

If the column list is not included in the REFERENCES option when defining a FOREIGN KEY constraint (single column or composite), ORACLE assumes that you intend to reference the primary key of the specified table. Alternatively, you can explicitly specify the column(s) to reference in the parent table within parentheses. ORACLE automatically checks to verify that this column list references a primary or unique key of the parent table. If it does not, an informative error is returned.

Privileges Required for FOREIGN KEY Integrity Constraints

To create a FOREIGN KEY constraint, the creator of the constraint must have privileged access to both the parent and the child table.

•	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 via a role; they must be explicitly granted to the creator of the constraint.

These restrictions allow:

•	the owner of the child table to explicitly decide what constraints are enforced on her tables and the other users that can create constraints on her tables

•	the owner of the parent table to explicitly decide if foreign keys can depend on the primary and unique keys in her tables

 Specifying Referential Actions for Foreign Keys

ORACLE allows two different types of referential integrity actions to be enforced, as specified with the definition of a FOREIGN KEY constraint:

•	The UPDATE/DELETE No Action Restriction  This action prevents the update or deletion of a parent key if there is a row in the child table that references the key. By default, all FOREIGN KEY constraints enforce the no action restriction; no option needs to be specified when defining the constraint to enforce the no action restriction. For example:

CREATE TABLE emp (

   . . .,

   FOREIGN KEY (deptno) REFERENCES dept);

•	The ON DELETE CASCADE Action  This action allows referenced data in the parent key to be deleted (but not updated). If referenced 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 definition of the FOREIGN KEY constraint. For example:

CREATE TABLE emp (

   . . .,

   FOREIGN KEY (deptno) REFERENCES dept

      ON DELETE CASCADE);

Enabling FOREIGN KEY Integrity Constraints

FOREIGN KEY integrity constraints cannot be enabled if the referenced primary or unique key's constraint is not present or not enabled.

________________________________________

Listing Integrity Constraint Definitions

The data dictionary contains the following views of interest with integrity constraints:

•	ALL_CONSTRAINTS

•	ALL_CONS_COLUMNS

•	CONSTRAINT_COLUMNS

•	CONSTRAINT_DEFS

•	USER_CONSTRAINTS

•	USER_CONS_COLUMNS

•	USER_CROSS_REFS

•	DBA_CONSTRAINTS

•	DBA_CONS_COLUMNS

•	DBA_CROSS_REFS

Refer to Appendix D for detailed information about each view.

Examples

Consider the following CREATE TABLE statements that define a number of integrity constraints, and the following examples:

CREATE TABLE dept (

   deptno   NUMBER(3) PRIMARY KEY,

   dname    VARCHAR2(15),

   loc      VARCHAR2(15),

   CONSTRAINT dname_ukey UNIQUE (dname, loc),

   CONSTRAINT loc_check1

      CHECK (loc IN ('NEW YORK', 'BOSTON', 'CHICAGO')));

CREATE TABLE emp (

   empno    NUMBER(5) PRIMARY KEY,

   ename    VARCHAR2(15) NOT NULL,

   job      VARCHAR2(10),

   mgr      NUMBER(5) CONSTRAINT mgr_fkey

            REFERENCES emp ON DELETE CASCADE,

   hiredate DATE,

   sal      NUMBER(7,2),

   comm     NUMBER(5,2),

   deptno   NUMBER(3) NOT NULL

   CONSTRAINT dept_fkey REFERENCES dept);

Example 1

Listing All of Your Accessible Constraints	The following query lists all constraints defined on all of the tables accessible to you, 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  C TABLE_NAME  R_CONSTRAINT_NAME

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

SYS_C00275       P DEPT

DNAME_UKEY       U DEPT

LOC_CHECK1       C DEPT

SYS_C00278       C EMP

SYS_C00279       C EMP

SYS_C00280       P EMP

MGR_FKEY         R EMP         SYS_C00280

DEPT_FKEY        R EMP         SYS_C00275

Notice the following

•	Some constraint names are user-specified (such as DNAME_UKEY), while others are system-specified (such as SYS_C00275).

•	Each constraint type is denoted with a different character in the CONSTRAINT_TYPE column. The table below summarizes the characters used for each constraint type.

Constraint Type	Character

PRIMARY KEY	P

UNIQUE KEY	U

FOREIGN KEY	R

CHECK, NOT NULL	C

Note: An additional constraint type is indicated by the character "V" in the CONSTRAINT_TYPE column. This constraint type corresponds to constraints created by the WITH CHECK OPTION for views. See Chapter 2 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 and DEPT tables, issue the following query:

SELECT constraint_name, search_condition

   FROM user_constraints

   WHERE (table_name = 'DEPT' OR table_name = 'EMP') AND

      constraint_type = 'C';

Considering the example statements at the beginning of this section, a list similar to the one below is returned:

CONSTRAINT_NAME  SEARCH_CONDITION

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

LOC_CHECK1       loc IN ('NEW YORK', 'BOSTON', 'CHICAGO')

SYS_C00278       ENAME IS NOT NULL

SYS_C00279       DEPTNO IS NOT NULL

Notice the following:

•	NOT NULL constraints are clearly identified in the SEARCH_CONDITION column.

•	The conditions for user-defined CHECK constraints are explicitly listed in the SEARCH_CONDITION column.

Example 3

Listing the Column Names that Constitute an Integrity Constraint 	The following query lists all columns that constitute the constraints defined on all of the 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  TABLE_NAME  COLUMN_NAME

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

DEPT_FKEY        EMP         DEPTNO

DNAME_UKEY       DEPT        DNAME

DNAME_UKEY       DEPT        LOC

LOC_CHECK1       DEPT        LOC

MGR_FKEY         EMP         MGR

SYS_C00275       DEPT        DEPTNO

SYS_C00278       EMP         ENAME

SYS_C00279       EMP         DEPTNO

SYS_C00280       EMP         EMPNO


CHAPTER 7. USING PROCEDURES AND PACKAGES

This chapter discusses the procedural capabilities of ORACLE. This chapter includes information on the following topics:

•	creating and debugging procedures and packages

•	invoking procedures

•	modifying a procedure or package

Note: The information in this chapter applies only to those systems using ORACLE with the procedural option. If using Trusted ORACLE, also see the Trusted ORACLE7 Server Administrator's Guide for important information about using the procedural option with Trusted ORACLE.

________________________________________

Creating Procedures and Packages

The following sections discuss the steps to create procedures and packages.

Prerequisites

Before you can create any procedures or packages, your database administrator, while connected as SYS, must submit the CATPROC.SQL script. This script automatically runs all of the scripts required for, or used within, the procedural option. The location of this file is operating system dependent; see your installation or user's guide.

General Recommendation for Creating Procedures and Packages

Use a text editor to write procedures and packages, and save the source code as a text file. Then, submit the procedure or package definition to ORACLE as a script. Using this method, you gain convenience in the following situations:

•	If a long procedure or package definition has a syntax error, you can easily correct and resubmit the corresponding text file using the script.

•	If you need to change a procedure or package definition, you can edit and resubmit the corresponding text file to replace the older version of the code.

ORACLE stores submitted source code for a procedure or package in the data dictionary. Source code can be retrieved using the following data dictionary views: ALL_SOURCE, USER_SOURCE, and DBA_SOURCE. See "Listing Information about Procedures and Packages" on page 7 - 22 for an example of these and other data dictionary views.

Creating Stand-Alone Procedures and Functions

A stand-alone stored procedure has two parts:

specification	The specification declares the procedure or function. The specification consists of this information:

•	the name of the procedure

•	the names and datatypes of any arguments

In addition, only for functions:

•	the datatype of the return value

body	The body defines the procedure or function. The procedure body consists of a PL/SQL block (SQL and PL/SQL statements).

Both parts of a procedure are created in one step using the CREATE PROCEDURE or CREATE FUNCTION command.

Use the SQL command CREATE PROCEDURE to create a procedure specification and body. You can issue this command from any interactive Oracle utility (such as SQL*Plus or SQL*DBA). The following statement creates the SAL_RAISE procedure:

CREATE PROCEDURE sal_raise (emp_id IN NUMBER,

                            sal_incr IN NUMBER) AS

/* The 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

   employee's salary). */

BEGIN

/* If employee exists, update salary with increase. */

   UPDATE emp

      SET sal = sal + sal_incr

      WHERE empno = emp_id;

   IF SQL%NOTFOUND THEN

      raise_application_error(-20011, 'Invalid Employee

         Number:'||TO_CHAR(emp_id));

   END IF;

END sal_raise;

When using SQL*DBA or SQL*Plus, denote the end of a CREATE PROCEDURE statement by ending that statement with a slash ("/") as the only character on the last line.

Use the SQL command CREATE FUNCTION to create a function specification and body. Issue the CREATE FUNCTION command from any interactive Oracle utility (SQL*Plus, SQL*DBA, etc.).

The following statement creates the specification and body of the HIRE_EMP function:

CREATE FUNCTION hire_emp (name VARCHAR2, job VARCHAR2,

   mgr NUMBER, hiredate DATE, sal NUMBER, comm NUMBER,

   deptno NUMBER) RETURN NUMBER IS

/* The 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. */

new_empno   NUMBER(10);    /* used for return value */

BEGIN

   SELECT emp_sequence.NEXTVAL INTO new_empno FROM dual;

   INSERT INTO emp VALUES (new_empno, name, job, mgr,

      hiredate, sal, comm, deptno);

   RETURN (new_empno);

END hire_emp;

Creating Packages

The declaration of a package has two parts:

package specification	The package specification contains the declarations of procedures (and functions), variables, constants, and exceptions that are accessible outside the package.

package body	The package body defines procedures (and functions), cursors, and exceptions that are declared in the package specification. The package body can also define procedures, variables, constants, cursors, and exceptions not declared in the package specification; however, these objects are only accessible within the scope of the package.

Each part of a package is created with a different command. Create the package specification using the CREATE PACKAGE command, and create the package body using the CREATE PACKAGE BODY command.

To create a package specification, use the CREATE PACKAGE command to declare public package objects. The following SQL statement creates the specification for the EMP_MGMT package:

CREATE PACKAGE emp_mgmt AS

   FUNCTION hire_emp (name VARCHAR2, job VARCHAR2,

      mgr NUMBER, hiredate DATE, sal NUMBER, comm NUMBER,

      deptno NUMBER) RETURN NUMBER;

   PROCEDURE fire_emp (emp_id NUMBER);

   PROCEDURE sal_raise (emp_id NUMBER, sal_incr NUMBER);

END emp_mgmt;

To create a package body, use the CREATE PACKAGE BODY command to specify the procedural code of the public procedures and functions declared in the package specification. You can also define private package procedures, variables, etc., within the package body. The following SQL statement creates the package body for the EMP_MGMT package:

CREATE PACKAGE BODY emp_mgmt AS

   FUNCTION hire_emp (name VARCHAR2, job VARCHAR2,

      mgr NUMBER, hiredate DATE, sal NUMBER, comm NUMBER,

      deptno NUMBER) RETURN NUMBER

   IS

/* The 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. */

   new_empno    NUMBER(10);

   BEGIN

      SELECT emp_sequence.NEXTVAL INTO new_empno FROM dual;

      INSERT INTO emp VALUES (new_empno, name, job, mgr,

         hiredate, sal, comm, deptno);

      RETURN (new_empno);

   END hire_emp;

   PROCEDURE fire_emp(emp_id IN NUMBER) AS

/* The procedure deletes the employee with an employee

   number that corresponds to the argument EMP_ID.  If

   no employee is found, an exception is raised. */

   BEGIN

      DELETE FROM emp 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

/* The 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

   employee's salary). */

    BEGIN

/* If employee exists, update salary with increase. */

      UPDATE emp

         SET sal = sal + sal_incr

         WHERE empno = emp_id;

      IF SQL%NOTFOUND THEN

         raise_application_error(-20011, 'Invalid Employee

            Number: ' ||TO_CHAR(emp_id));

      END IF;

   END sal_raise;

END emp_mgmt;

Declaring Public and Private Data and Procedures within Packages    Declare a procedure, variable, constant, cursor, or exception in either the package specification or package body, making the package construct either public or private, respectively.

Declare a public procedure, variable, constant, cursor, or exception in a package specification, making it available outside of the package as well as within the package. Public constructs are declared in the following situations:

•	A public procedure can be executed by privileged users of the package.

•	A public variable, constant, or cursor can be used by procedures or statements external to the package, assuming the owner of a procedure or user that issues a statement has EXECUTE privilege for the package.

•	A public exception can be used by external procedures, assuming the owner of the procedure has EXECUTE privilege for the package.

To declare a public package construct, include its declaration in the package specification. After a public procedure is declared in the package specification, it must be defined in the package body.

A private procedure, variable, constant, cursor, or exception is not declared in the package specification. Therefore, it is available only in the scope of the package body (if declared in the package body) or the scope of the procedure (if declared in a package procedure).

Use private constructs when tighter security must be maintained for the execution of a package procedure or the availability of a package's variables or cursors.

Procedure and Package Variables, Constants, and Cursors     Variables, constants, and cursors are different from other language constructs because they have state or a value that can change and persist for a specific lifetime. The duration of a variable's, constant's, or cursor's state depends on the location of its declaration:

procedure variables, constants, and cursors	The state of a variable, constant, or cursor declared in a stand-alone procedure or package procedure persists only for the duration of a procedure call and is lost when the procedure execution terminates.

package variables, constants, and cursors	The state of a variable, constant, or cursor declared in the specification or body of a package (that is, not within a procedure) persists for the duration of the user's session (that is, across transactions). State is lost when the current session ends or the package is recompiled.

Package variables, constants, and cursors have some unique considerations:

•	Every session of a package has its own set of package variables, constants, and cursors.

•	When a session begins, the values of the package variables and cursors are NULL until initialized. Your applications should always initialize all package variables, either declaratively or using an initialization procedure.

•	During a session, the package user can modify the values of the package variables and cursors. When a user disconnects from the database and terminates the current session, the values of a package's variables and cursors are lost.

Procedure variables and cursors are preferred unless persistent state is required for the processing of data among several procedure calls within the context of a transaction or between transactions.

Automatic First-Time-Only Code     An optional block of code can be included in the definition of a package body that is executed when a session first instantiates the package. This code is often used to initialize package variables.

Define automatic first-time-only code for a package in a BEGIN ... END block in the package body. The following statement creates a package body for the BANK_TRANSACTIONS package, including first-time-only code (in bold) to initialize a new private variable that gets the current teller's (session's) username:

CREATE PACKAGE BODY bank_transactions AS

   teller_name VARCHAR2;

   PROCEDURE do_journal_entry(acct NUMBER, kind CHAR) IS

      BEGIN ... END;

   PROCEDURE credit_account(acct NUMBER, credit NUMBER) IS

      BEGIN ... END;

   PROCEDURE debit_account(acct NUMBER, debit NUMBER) IS

      BEGIN ... END;

   PROCEDURE apply_transaction;

   PROCEDURE enter_transaction(acct NUMBER, kind CHAR,

      amount NUMBER, teller_id VARCHAR2) IS

      BEGIN ... END;

BEGIN

   SELECT USER INTO teller_id FROM dual;

END bank_transactions;

Overloading of Package Procedure Names    PL/SQL allows two or more procedures in the same package to have the same name. This option is useful in situations where you would like a procedure to accept arguments of different datatypes. A good example of overloaded package procedure names is the PUT_LINE procedure of the DBMS_OUTPUT package; see Appendix A.

Naming Procedures, Functions, and Packages

The name of a procedure, function, or package must be unique within a given schema. A package's specification and body must have the same name. All package constructs must have unique names within the scope of the package, unless overloading of procedure names is desired.

Package Invalidations and Session State

Each session that references a package construct has its own instance of the corresponding package, including persistent state for any public and private variables, cursors, and constants. All of a session's package instantiations (including state) can be lost if any of the session's instantiated packages (specification or body) are subsequently invalidated and recompiled. For example, if session S instantiates packages P1 and P2, and P1 is invalidated and recompiled (for example, as the result of some type of DDL operation), session S's instantiations of P1 and P2 are lost. In such situations, a session receives this error the first time it attempts to use any construct of an invalidated package instantiation:

ORA-04068: existing state of packages has been discarded

Note: The second time a session makes such a package call, the package is reinstantiated for the session without error.

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 specification or body invalidations are common in your system during working hours, you might want to code your applications to detect for this error when package calls are made. For example, the user-side application might reinitialize any user-side state that depends on any session's package state (that was lost) and reissue the package call.

Valid Statements and Restrictions for Procedures and Packages

The body of a stand-alone procedure or package procedure is any valid PL/SQL block, which can contain any DML SQL statement, including SELECT (must be SELECT ... INTO ... statement or SELECT statements in the definition of a cursor), SELECT ... FOR UPDATE, INSERT, UPDATE, DELETE, and LOCK statements, and any PL/SQL code.

A procedure that includes the transaction control statements COMMIT, ROLLBACK, and SAVEPOINT cannot be executed by a trigger or a procedure participating in a distributed transaction; a runtime error is returned in such cases.

The SESSION_ROLES view does not work within a stored procedure. Although certain ORACLE functionality is not available to PL/SQL users (for example, a COMMIT statement in a PL/SQL program unit cannot include the FORCE option), standard packaged procedures are available to provide this functionality. These procedures are described in Appendix A of this document.

The following list explains how the LONG and LONG RAW datatypes can and cannot be used within PL/SQL program units:

•	A SQL statement within a procedure or package 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 or VARCHAR2), a LONG or LONG RAW column can be referenced in a SQL statement within a procedure or package. Note that the longest PL/SQL datatype is 32 Kbytes.

Privileges Required to Create Procedures and Packages

To create a stand-alone procedure or function, or package specification or body, you must meet the following prerequisites:

•	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 user's schema.

To create without errors, that is, to compile the procedure or package successfully, requires the following additional privileges:

•	The owner of the procedure or package must have been explicitly granted the necessary object privileges to all objects referenced within the body of the code; the owner cannot have obtained required privileges through roles.

Note: If the privileges of a procedure's or package's owner change, the procedure must be reauthenticated before it is executed. If a necessary privilege to a referenced object is revoked from the owner of the procedure (or package), the procedure cannot be executed.

The EXECUTE privilege on a procedure gives a user the right to execute a procedure owned by another user. Privileged users execute the procedure under the security domain of the procedure's owner. Therefore, users never have to be granted the privileges to the objects referenced by a procedure. This fact allows for more disciplined and efficient security strategies with database applications and their users. Furthermore, all procedures and packages are stored in the data dictionary (that is, the SYSTEM tablespace). No quota controls the amount of space available to a user that creates procedures and packages.

Handling Errors

ORACLE allows user-defined errors in PL/SQL code to be handled so user-specified error numbers and messages are returned to the client application. Once received, the client application can handle the error based on the user-specified error number and message returned by ORACLE.

User-specified error messages are returned using the RAISE_APPLICATION_ERROR procedure:

RAISE_APPLICATION_ERROR(error_number, 'text', keep_error_stack)

This procedure terminates procedure execution, rolls back any effects of the procedure, and returns a user-specified error number and message. 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 already on the stack, or FALSE, if you want to replace the existing errors. By default, this option is FALSE.

The RAISE_APPLICATION_ERROR procedure is often used in exception handlers or the logic of PL/SQL code. For example, the following exception handler selects the string for the associated user-defined 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.name = "NLS_LANGUAGE";

   raise_application_error(-20101, message);

...

Several examples earlier in this chapter also demonstrate the use of the RAISE_APPLICATION_ERROR procedure. The next section has an example of passing a user-specified error number from a trigger to a procedure. For information on exception handling when calling remote procedures, see page 11 - 5.

Declaring Exceptions and Exception Handling Routines

User-defined exceptions are explicitly defined and signaled within the PL/SQL block to control processing of errors specific to the application. When an exception is raised (signaled), the normal execution of the PL/SQL block stops and a routine called an exception handler is invoked. Specific exception handlers can be written to handle any internal or user-defined exception.

Application code can check for a condition that requires special attention using an IF statement. If there is an error condition, two options are available:

•	Issue 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-specified error number and message.

In conjunction with the above procedures, you can define an exception handler to handle user-specified error messages. For example, Figure 7 - 1 illustrates:

•	an exception and associated exception handler in a procedure

•	a conditional statement that checks for an error (such as transferring funds not available) and issues a user-specified error number and message within a trigger

•	how user-specified error numbers are returned to the calling environment (in this case, a procedure) and how that application can define an exception that corresponds to the user-specified error number

Declare a user-defined exception handler in a procedure or package body (private exceptions) or in the specification of a package (public exceptions). Define an exception handler in the body of a procedure (stand-alone or package).

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 prior to the point at which the unhandled exception is observed, 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, the database PL/SQL program unit should be fixed. Your application can also trap for unhandled exceptions when calling database program units and handle such errors appropriately. For information on exception handling when calling remote procedures, see page 11 - 5.

________________________________________

Identifying Compilation Errors for Procedures and Packages

If programming errors (such as invalid syntax) or incorrect security authorizations are present when creating, replacing, and compiling a procedure or package, a tool-specific error is returned. SQL*DBA returns the following message if compilation errors are detected when compiling a procedure or package:

DBA-00072: Warning: object created with compilation errors.

where object is the name of the procedure or package just created.

Display all errors associated with the most recently created procedure or package using the SQL*DBA command SHOW ERRORS. For example, assume you want to create a simple procedure that deletes records from the employee table using SQL*DBA:

CREATE PROCEDURE fire_emp(emp_id NUMBER) AS

   BEGIN

      DELETE FROM emp 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 absent after END.

After the CREATE PROCEDURE statement is issued and an error is returned, a SHOW ERRORS statement would return the following lines:

SHOW ERRORS;

ERRORS FOR PROCEDURE FIRE_EMP:

LINE/COL       ERROR

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

3/24   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 command.

Alternatively, you can query the following data dictionary views to list errors when using any tool or application:

•	USER_ERRORS

•	ALL_ERRORS

•	DBA_ERRORS

The error text associated with the compilation of a procedure is updated when the procedure is replaced, and 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 Appendix D for more information about these data dictionary views.

________________________________________

Debugging Procedures and Packages

To aid in the development of stored procedures, packages, and triggers, a public package, named DBMS_OUTPUT, is provided for displaying debugging information. The procedures in this package provide much the same functionality as the printf() function in C. For a complete explanation of each of these procedures, see Appendix A of this Guide.

Creating the DBMS_OUTPUT Package

To create the DBMS_OUTPUT package, submit the DBMSOTPT.SQL script when connected as the user SYS. This script is run automatically by the CATPROC.SQL script.

Including Debugging Information in a File

To include debugging information in your stored procedure, package, or trigger, use the PUT or PUT_LINE procedures. The PUT procedure allows you to add multiple pieces of information to the buffer before calling the NEW_LINE procedure to end a line. The PUT_LINE procedure adds a single line of information to the buffer.

To display this information when the trigger or procedure is executed, you can use either of the following options:

•	Use the GET_LINE or GET_LINES procedure to retrieve one or more lines of information from the buffer.

•	Enable the server output option (SET SERVEROUTPUT ON) in SQL*DBA or SQL*Plus before executing the procedure or package. The debugging information is displayed automatically.

Example of Using DBMS_OUTPUT

An example of a function that queries the employee table and returns the total salary for a specified department follows. The function includes several calls to the PUT_LINE procedure:

CREATE FUNCTION dept_salary (dnum NUMBER) RETURN NUMBER IS

   CURSOR emp_cursor IS

      SELECT sal, comm FROM emp WHERE deptno = dnum;

   total_wages    NUMBER(11, 2) := 0;

   counter        NUMBER(10) := 1;

BEGIN

   FOR emp_record IN emp_cursor LOOP

      emp_record.comm := NVL(emp_record.comm, 0);

      total_wages := total_wages + emp_record.sal

         + emp_record.comm;

      DBMS_OUTPUT.PUT_LINE('Loop number = ' || counter ||

         '; Wages = '|| TO_CHAR(total_wages));  /* Debug line */

      counter := counter + 1; /* Increment debug counter */

   END LOOP;

   /* Debug line */

   DBMS_OUTPUT.PUT_LINE('Total wages = ' ||

     TO_CHAR(total_wages));

   RETURN total_wages;

END dept_salary;

Assume the EMP table contains the following rows:

EMPNO          SAL     COMM     DEPT

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

1002           1500      500      20

1203           1000               30

1289           1000               10

1347           1000      250      20

Assume the following statements are issued at the SQL*DBA prompt:

SQLDBA>SET SERVEROUTPUT ON

SQLDBA>VARIABLE salary NUMBER;

SQLDBA>EXECUTE :salary := dept_salary(20);

As a result, the following information is displayed

Loop number = 1; Wages = 2000

Loop number = 2; Wages = 3250

Total wages = 3250

PL/SQL procedure successfully executed.

________________________________________

Invoking Procedures

Procedures can be invoked from many different environments. For example:

•	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 (such as SQL*Plus)

•	A procedure can be explicitly called within an application (such as a SQL*Forms or precompiler application).

Some common examples of invoking procedures from within these environments follow.

A Procedure or Trigger Calling Another Procedure

A procedure or trigger can call another stored procedure. For example, included in the body of one procedure might be the line:

. . .

sal_raise(emp_id, 200);

. . .

This line calls the SAL_RAISE procedure. EMP_ID is a variable within the context of the procedure. Note that recursive procedure calls are allowed within PL/SQL; that is, a procedure can call itself.

Interactively Invoking Procedures From ORACLE Tools

A procedure can be invoked interactively from an Oracle tool such as SQL*DBA. For example, to invoke a procedure named SAL_RAISE, owned by you, use the EXECUTE command:

EXECUTE sal_raise(1043, 200);

Some interactive tools allow session variables to be created. For example, when using SQL*DBA, the following statement creates a session variable:

VARIABLE assigned_empno NUMBER;

Once defined, any session variable can be used for the duration of the session. For example, you might execute a function and capture the return value using a session variable:

EXECUTE :assigned_empno := hire_emp('TSMITH', 'CLERK', \

   1032, SYSDATE, 500, NULL, 10);

PRINT assigned_empno;

ASSIGNED_EMPNO

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

          2893

See the ORACLE7 Server Utilities User's Guide for SQL*DBA information. See your tools manuals for information about performing similar operations using your tool.

Explicitly Calling Procedures within Applications

A database application (such as a precompiler application or OCI application) can include a call to a procedure within the code of the application.

To execute a procedure within a PL/SQL block of an application, simply call the procedure. The following line within a PL/SQL block calls the FIRE_EMP procedure:

fire_emp(:empno);

In this case, :EMPNO is a host (bind) variable within the context of the application.

To execute 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_emp(:empno);

   END;

END-EXEC;

:EMPNO is a host (bind) variable.

Name Resolution When Invoking Procedures

References to procedures and packages are resolved according to the algorithm described in the section "Name Resolution of Objects Referenced in SQL Statements" on page 2 - 34.

Privileges Required to Execute a Procedure

If you are the owner of a stand-alone procedure or package, you can execute the stand-alone procedure or packaged procedure, or any public procedure or packaged procedure at any time, as described in the previous sections. If you want to execute a stand-alone or packaged procedure owned by another user the following conditions apply:

•	You must have the EXECUTE privilege for the stand-alone procedure or package containing the procedure, or have the EXECUTE ANY PROCEDURE system privilege. If you are executing a remote procedure, you must have been granted the EXECUTE privilege or EXECUTE ANY PROCEDURE system privilege directly, not via a role.

•	You must include the owner's name in the call, as in:

EXECUTE jward.fire_emp (1043);

EXECUTE jward.hire_fire.fire_emp (1043);

Specifying Values for Procedure Arguments

When you invoke a procedure, specify a value or parameter for each of the procedure's arguments. Identify the argument values using either of the following methods, or a combination of both:

•	List the values in the order the arguments appear in the procedure declaration.

•	Specify the argument names and corresponding values, in any order.

For example, these statements each call the procedure UPDATE_SAL 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 first statement identifies the argument values by listing them in the order in which they appear in the procedure specification.

The second statement identifies the argument values by name and in an order different from that of the procedure specification. If you use argument names, you can list the arguments in any order.

The third statement identifies the argument values using a combination of these methods. If you use a combination of order and argument names, values identified in order must precede values identified by name.

If you have used the DEFAULT option to define default values for IN parameters to a subprogram (see the PL/SQL User's Guide and Reference), you can pass different numbers of actual parameters to the subprogram, accepting or overriding the default values as you please. If an actual value is not passed, 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), you must explicitly designate the name of the argument, as well as its value.

Invoking Remote Procedures

Invoke remote procedures using an appropriate database link and the procedure's name. The following SQL*DBA statement executes the procedure FIRE_EMP located in the database pointed to by the local database link named NY:

EXECUTE fire_emp@NY(1043);

For information on exception handling when calling remote procedures, see page 11 - 5.

Referencing Remote Objects

Remote objects can be referenced within the body of a locally defined procedure. The following procedure deletes a row from the remote employee table:

CREATE PROCEDURE fire_emp(emp_id NUMBER) IS

BEGIN

    DELETE FROM emp@sales WHERE empno = emp_id;

END;

The list below explains how to properly call remote procedures, depending on the calling environment.

•	Remote procedures (stand-alone and packaged) can be called from within a procedure, OCI application, or precompiler application by specifying the remote procedure name, a database link, and the arguments for the remote procedure.

CREATE PROCEDURE local_procedure(arg1, arg2) AS

BEGIN

   . .

   remote_procedure@dblink(arg1, arg2);

   . .

END;

•	In the previous example, you could create a synonym for REMOTE_PROCEDURE@DBLINK. 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 PROCEDURE local_procedure(arg1, arg2) AS

BEGIN

   . .

   synonym(arg1, arg2);

   . .

END;

•	If you did not want to use a synonym, you could write a local cover procedure to call the remote procedure.

BEGIN local_procedure(arg1, arg2); END;

Here, LOCAL_PROCEDURE is defined as in the first item of this list.

Note: Synonyms can be used to create location transparency for the associated remote procedures.

Warning: Unlike stored procedures, which use compile-time binding, when referencing remote procedures, runtime binding is used. 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, the work done by the remote procedure is also rolled back. A procedure called remotely cannot execute a COMMIT, ROLLBACK, or SAVEPOINT statement.

A distributed update modifies 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, 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, the remote procedure is not executed and the local procedure is invalidated.

Synonyms for Procedures and Packages

Synonyms can be created for stand-alone procedures and packages to:

•	hide the identity of the name and owner of a procedure or package

•	provide location transparency for remotely stored procedures (stand-alone or within a package)

When a privileged user needs to invoke a procedure, an associated synonym can be used. Because the procedures defined within a package are not individual objects (that is, the package is the object), synonyms cannot be created for individual procedures within a package.

________________________________________

Replacing Procedures and Packages

A stand-alone procedure or package cannot be explicitly altered; it must be replaced with a new definition of the procedure or package. For example, if you want to slightly alter one of the statements in the body of a stand-alone procedure, you cannot only alter that single statement. Instead, you must recreate the entire procedure with the modification. If you use a text editor to create your procedures and packages, you can simply edit the corresponding text file and execute the CREATE PROCEDURE or CREATE PACKAGE BODY statement to define the new version of the code. Similarly, you cannot redefine a specific procedure within the body of a package; you must replace the entire package body.

When replacing a procedure or package, you must include the OR REPLACE option in the CREATE PROCEDURE, CREATE FUNCTION, CREATE PACKAGE, or CREATE PACKAGE BODY statement. The OR REPLACE option is provided to allow a newer version of an existing procedure or package to replace the older version without affecting any grants made for the original version of the procedure or package.

Note: Alternatively, a procedure can be dropped and recreated. However, all grants made for the dropped procedure are also dropped and must be granted again when the new version of the procedure is created.

For example, assume that you already own a procedure named SAL_RAISE or a package named HIRE_FIRE. When you subsequently issue a CREATE PROCEDURE or CREATE PACKAGE BODY statement to create a new version of the procedure or package body by the same name, you must include the OR REPLACE option in that statement:

CREATE OR REPLACE PROCEDURE sal_raise . . . END;

CREATE OR REPLACE PACKAGE BODY hire_fire . . . END hire_fire;

If you do not include the OR REPLACE option when a procedure or package by the same name currently exists, an error is issued and the existing procedure or package is not altered.

________________________________________

Dropping Stand-Alone Procedures and Packages

A stand-alone procedure, a stand-alone function, a package body, or an entire package can be dropped using the SQL commands DROP PROCEDURE, DROP FUNCTION, DROP PACKAGE BODY, and DROP PACKAGE, respectively. A DROP PACKAGE statement drops both a package's specification and body.

The following statement drops the OLD_SAL_RAISE procedure in your schema:

DROP PROCEDURE old_sal_raise;

Privileges Required to Drop Procedures and Packages

To drop a procedure 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 specification and body must be recreated without the procedures to be dropped.

________________________________________

Dependency Issues

There are several dependency issues to consider before dropping a procedure or package. Information about dependency issues is included in Chapter 9.

________________________________________

Listing Information about Procedures and Packages

The following data dictionary views provide information about procedures and packages:

•	ALL_ERRORS, USER_ERRORS, DBA_ERRORS

•	ALL_SOURCE, USER_SOURCE, DBA_SOURCE

•	USER_OBJECT_SIZE, DBA_OBJECT_SIZE

The *_OBJECT_SIZE views show the sizes of the PL/SQL objects. For a complete description of these data dictionary views, see Appendix D.

The following statements are used in Examples 1 through 3:

CREATE PROCEDURE fire_emp(emp_id NUMBER) AS

BEGIN

   DELETE FROM em WHERE empno = emp_id;

END;

/

CREATE PROCEDURE hire_emp (name VARCHAR2, job VARCHAR2,

   mgr NUMBER, hiredate DATE, sal NUMBER,

   comm NUMBER, deptno NUMBER)

IS

BEGIN

   INSERT INTO emp VALUES (emp_sequence.NEXTVAL, name,

      job, mgr, hiredate, sal, comm, deptno);

END;

/

The first CREATE PROCEDURE statement has an error in the DELETE statement. (The 'p' is absent from 'emp'.)

Example 1

Listing Compilation Errors for Objects	The following query returns all the errors for the objects in the associated schema:

SELECT name, type, line, position, text

FROM user_errors;

The following results are returned:

NAME     TYPE LIN POS TEXT

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

FIRE_EMP PROC   3  15 PL/SQL-00201: identifier 'EM' must be

                                    declared

FIRE_EMP PROC   3   3 PL/SQL: SQL Statement ignored

Example 2

Listing Source Code for a Procedure	The following query returns the source code for the HIRE_EMP procedure created in the example statement at the beginning of this section:

SELECT line, text FROM user_source

WHERE name = 'HIRE_EMP';

The following results are returned:

LINE   TEXT

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

     1 PROCEDURE hire_emp (name VARCHAR2, job VARCHAR2,

     2    mgr NUMBER, hiredate DATE, sal NUMBER,

     3    comm NUMBER, deptno NUMBER)

     4 IS

     5 BEGIN

     6    INSERT INTO emp VALUES (emp_seq.NEXTVAL, name,

     7    job, mgr, hiredate, sal, comm, deptno);

     8 END;

Example 3

Listing Size Information for a Procedure	The following query returns information about the amount of space in the SYSTEM tablespace that is required to store the HIRE_EMP procedure:

SELECT name, source_size + parsed_size + code_size +

      error_size "TOTAL SIZE"

   FROM user_object_size

   WHERE name = 'HIRE_EMP';

The following results are returned:

NAME                           TOTAL SIZE

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

HIRE_EMP                             3897


CHAPTER 8. USING DATABASE TRIGGERS

This chapter discusses database triggers-procedures that are stored in the database and implicitly executed ("fired") when a table is modified. Topics include:

•	creating, debugging, altering, dropping, enabling, and disabling triggers

•	sample trigger applications

The information in this chapter applies only to those systems using ORACLE with the procedural option. If using Trusted ORACLE, see the Trusted ORACLE7 Server Administrator's Guide for more information about defining and using database triggers.

________________________________________

Designing Triggers

Use the following guidelines when designing triggers:

•	Use triggers to guarantee that when a specific operation is performed, related actions are performed.

•	Only use database triggers for centralized, global operations that should be fired for the triggering statement, regardless of which user or database application issues the statement.

•	Do not define triggers to duplicate the functionality already built into ORACLE. For example, do not define triggers to enforce data integrity rules that can be easily enforced using declarative integrity constraints.

Warning: Be careful not to create recursive triggers. For example, creating an AFTER UPDATE statement trigger on the EMP table that itself issues an UPDATE statement on EMP, causes the trigger to fire recursively until it has run out of triggers

Because a trigger must be compiled when it is first fired (and upon subsequent firings if it has aged out of its shared context area), it is a good idea to limit the size of triggers (roughly 60 lines). Compilation of smaller triggers will have an insignificant effect on system performance. If a trigger must execute many lines, it is preferable to include the code that the trigger must execute in a stored procedure (which is stored in compiled form). This way, the trigger can call the compiled, stored procedure, avoiding compilation time.

________________________________________

Creating Triggers

Triggers are created using the CREATE TRIGGER command. This command can be used with any interactive tool (such as SQL*Plus or SQL*DBA); when using such tools, a slash ("/") by itself on the last line is used to denote the end of the CREATE TRIGGER statement. The following statement creates a trigger associated with the EMP table:

CREATE TRIGGER dummy

BEFORE DELETE OR INSERT OR UPDATE ON emp

FOR EACH ROW

WHEN (new.empno > 0)

DECLARE

   /* variables, constants, cursors, etc. */

BEGIN

   /* PL/SQL block */

END;

/

The CREATE statement fails if any errors exist in the PL/SQL block.

The following sections use this example to illustrate the way that parts of a trigger are specified. For more realistic examples of CREATE TRIGGER statements, see "Examples of Trigger Applications" on page 8 - 14.

Prerequisites

Before creating any triggers, while connected as SYS, submit the CATPROC.SQL script. This script automatically runs all of the scripts required for, or used within, the procedural option. The location of this file is operating system dependent; see your installation or user's guide.

Naming Triggers

Trigger names must be unique with respect to other triggers in the same schema. Trigger names do not have 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 (although, to avoid confusion, this is not recommended).

The BEFORE/AFTER Options

Either the BEFORE or AFTER option must be used in the CREATE TRIGGER statement to specify exactly when the trigger body is fired in relation to the triggering statement being executed. In a CREATE TRIGGER statement, the BEFORE or AFTER option is specified just before the triggering statement. For example, the DUMMY trigger in the previous example is a BEFORE trigger.

Suggestion: AFTER row triggers are slightly more efficient 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 need only be read once for both the triggering statement and the trigger.

Triggering Statement

The triggering statement specifies:

•	the type of SQL statement that fires the trigger body. The possible options include DELETE, INSERT, and UPDATE. One, two, or all three of these options can be included in the triggering statement specification.

•	the table associated with the trigger. Note that exactly one table (not a view) can be specified in the triggering statement.

For example, the DUMMY trigger's triggering statements are any DELETEs, INSERTs, or UPDATEs on the EMP table. Any of the following statements would trigger the DUMMY trigger given in the previous example:

DELETE FROM emp;

INSERT INTO emp VALUES ( . . . );

INSERT INTO emp SELECT . . . FROM . . . ;

UPDATE emp SET . . . ;

Column List for UPDATE     If a triggering statement specifies UPDATE, an optional list of columns can be included in the triggering statement. If you include a column list, the trigger is fired on an UPDATE statement only when one of the specified columns is updated. If you omit a column list, the trigger is fired when any column of the associated table is updated. A column list cannot be specified for INSERT or DELETE triggering statements.

The previous example of the DUMMY trigger might have included a column list in the triggering statement, as in:

. . . BEFORE DELETE OR INSERT OR UPDATE OF ename ON emp . . .

FOR EACH ROW Option

The presence or absence of the FOR EACH ROW option determines whether the trigger is a row trigger or a statement trigger. If included, this option specifies that the trigger body is fired individually for each row of the table affected by the triggering statement. The absence of the FOR EACH ROW option implies that the trigger should only be fired once for the triggering statement.

The WHEN Clause

Optionally, a trigger restriction can be included in the definition of a row trigger by specifying a Boolean SQL expression in a WHEN clause (a WHEN clause cannot be included in the definition of a statement trigger). If included, the expression in the WHEN clause is evaluated for each row that the trigger affects. If the expression evaluates to TRUE for a row, the trigger body is fired on behalf of that row. However, if the expression evaluates to FALSE or NOT TRUE (that is, unknown, as with nulls) for a row, the trigger body is not fired for that row. The evaluation of the WHEN clause does not have an affect on the execution of the triggering SQL statement (that is, the triggering statement is not rolled back if the expression in a WHEN clause evaluates to FALSE).

For example, in the DUMMY trigger, the trigger body would not be executed 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 below. The expression in a WHEN clause must be a SQL expression (not a PL/SQL expression) and cannot include a subquery.

The Trigger Body

The trigger body is a PL/SQL block that can include SQL and PL/SQL statements. These statements are executed if the triggering statement is issued and the trigger restriction (if included) evaluates to TRUE. The trigger body for row triggers has some special constructs that can be included in the code of the PL/SQL block:  correlation names and the REFERENCING option, and the conditional predicates INSERTING, DELETING, and UPDATING.

Accessing Column Values in Row Triggers

Within a trigger body of a row trigger, the PL/SQL code and SQL statements have access to the old and new column values of the current row affected by the triggering statement. Two correlation names exist for every column of the table being modified: one for the old column value and one for the new column value. Depending on the type of triggering statement, certain correlation names might not have any meaning.

•	A trigger fired 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 fired by an UPDATE statement has access to both old and new column values for both BEFORE and AFTER row triggers.

•	A trigger fired by a DELETE statement has meaningful access to old column values only. Because the row will no longer exist after the row is deleted, the new values are NULL.

The new column values are referenced using the NEW qualifier before the column name, while the old column values are referenced using the OLD qualifier before the column name. For example, if the triggering statement is associated with the EMP table (with the columns SAL, COMM, etc.), you can include statements in the trigger body similar to:

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 fired). If a BEFORE row trigger changes the value of NEW.COLUMN, an AFTER row trigger fired 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 qualifiers when they are used in a trigger's body, but a colon is not allowed when using the qualifiers in the WHEN clause or the REFERENCING option.

 The REFERENCING Option

The REFERENCING option can be specified in a trigger body of a row trigger to avoid name conflicts among the correlation names and tables that might be named "OLD" or "NEW." Since this is rare, this option is infrequently used.

For example, assume you have a table named NEW with columns FIELD1 (number) and FIELD2 (character). The following CREATE TRIGGER example shows a trigger associated with the NEW table that can use correlation names and avoid naming conflicts between the correlation names and the table name:

CREATE TRIGGER dummy

BEFORE UPDATE ON new

REFERENCING new AS newest

FOR EACH ROW

BEGIN

   :newest.field2 := TO_CHAR (:newest.field1);

END;

Notice that the NEW qualifier is renamed to NEWEST using the REFERENCING option, and then used in the trigger body.

Conditional Predicates

If a trigger can be fired by more than one type of DML operation (for example, "INSERT OR DELETE OR UPDATE OF emp"), the trigger body can use the conditional predicates INSERTING, DELETING, and UPDATING to execute specific blocks of code, depending on the type of statement that fires the trigger. Assume this is the triggering statement:

INSERT OR UPDATE ON emp

Within the code of the trigger body, you can include the following conditions:

IF INSERTING THEN . . . END IF;

IF UPDATING THEN . . . END IF;

The first condition evaluates to TRUE only if the statement that fired the trigger is an INSERT statement; the second condition evaluates to TRUE only if the statement that fired the trigger is an UPDATE statement.

In an UPDATE trigger, a column name can be specified with an UPDATING conditional predicate to determine if the named column is being updated. For example, assume a trigger is defined as:

CREATE TRIGGER . . .

. . . UPDATE OF sal, comm ON emp . . .

BEGIN

. . . IF UPDATING ('SAL') THEN . . . END IF;

END;

The code in the THEN clause executes only if the triggering UPDATE statement updates the SAL column. The following statement would fire the above trigger and cause the UPDATING (sal) conditional predicate to evaluate to TRUE:

UPDATE emp SET sal = sal + 100;

 Error Conditions and Exceptions in the Trigger Body

If a predefined or user-defined error condition or exception is raised during the execution of a trigger body, all effects of the trigger body, as well as the triggering statement, are rolled back (unless the exception is specifically handled). Therefore, a trigger body can prevent the execution of the triggering statement by raising an exception. User-defined exceptions are commonly used in triggers that enforce complex security authorizations or integrity constraints.

For more information about error processing in PL/SQL program units, see "Handling Errors" and "Declaring Exceptions and Exception Handling Routines," on page 7 - 11.

 Restrictions on Creating Triggers

The following sections discuss restrictions imposed for triggers.

Number of Triggers Per Table     Only one trigger of each type can exist per table. This allows for twelve possible triggers per table:

BEFORE UPDATE row 	AFTER UPDATE row

BEFORE DELETE row 	AFTER DELETE row

BEFORE INSERT statement 	AFTER INSERT statement

BEFORE INSERT row 	AFTER INSERT row

BEFORE UPDATE statement 	AFTER UPDATE statement

BEFORE DELETE statement	AFTER DELETE statement.

If you attempt to duplicate any type of a trigger for a table, a compile-time error is returned.

Note: Each table can have up to four UPDATE triggers (BEFORE/AFTER, statement/row), regardless of whether the triggers are fired only when specific columns are updated.

Valid SQL Statements in Trigger Bodies     The body of a trigger can contain DML SQL statements, including SELECT (must be SELECT ... INTO ... statement or SELECT statement in the definition of a cursor), INSERT, UPDATE, and DELETE statements; DDL statements are not allowed in the body of a trigger. Transaction control cannot be performed within the context of a trigger. Therefore, the following SQL statements are not permitted within the context of a trigger body: ROLLBACK, COMMIT, and SAVEPOINT.

Note: A procedure called by a trigger cannot execute the above transaction control statements because the procedure executes within the context of the trigger body.

Statements inside a trigger can reference remote objects. However, pay special attention when calling remote procedures from within a local trigger; if a timestamp mismatch is found during execution of the trigger, the remote procedure is not executed and the trigger is invalidated.

Use of LONG and LONG RAW Datatypes in Triggers     The following list explains how the LONG and LONG RAW datatypes can and cannot be used within triggers:

•	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), a LONG or LONG RAW column can be referenced in a SQL statement within a trigger. Note that the maximum length for these datatypes is 32 Kbytes.

•	Variables cannot be declared using the LONG or LONG RAW datatypes.

•	:NEW and :OLD cannot be used with LONG or LONG RAW columns.

Tables with Snapshot Logs     The creation of a snapshot log implicitly creates an AFTER ROW trigger on a master table. Therefore, a user-defined AFTER row trigger cannot be defined for master tables with snapshot logs. Conversely, a snapshot log cannot be created for a table that has an AFTER row trigger; the trigger must first be dropped. Snapshots and snapshot logs are discussed in Chapter 12.

References to Package Variables     If an UPDATE or DELETE statement detects a conflict with a concurrent UPDATE, ORACLE performs a transparent rollback to savepoint and restarts the update. This can occur many times before the statement completes successfully. Each time the statement is restarted, the BEFORE STATEMENT trigger is refired. The rollback to savepoint does not undo changes to any package variables referenced in the trigger. The package should include a counter variable to detect this situation.

Row Evaluation Order     A relational database does not guarantee the order of rows processed by a SQL statement. Therefore, do not create triggers that depend on the order in which rows will be processed. For example, do not assign a value to a global package variable in a row trigger if the current value of the global variable is dependent on the row being processed by the row trigger. Also, if global package variables are updated within a trigger, it is best to initialize those variables in a BEFORE statement trigger.

When a statement in a trigger body causes another trigger to be fired, the triggers are said to be cascading. ORACLE allows up to 32 triggers to cascade at any one time. However, you can effectively limit the number of trigger cascades using the initialization parameter MAX_OPEN_CURSORS; a cursor must be opened for every execution of a trigger.

Mutating and Constraining Tables   A mutating table is a table that is currently being modified by an UPDATE, DELETE, or INSERT statement, or a table that might need to be updated by the effects of a declarative DELETE CASCADE referential integrity action. A constraining table is a table that a triggering statement might need to read either directly, for a SQL statement, or indirectly, for a declarative referential integrity constraint. A table is mutating or constraining only to the session that issued the statement in progress.

A table is not considered mutating or constraining for statement triggers; however, there are two important restrictions on row triggers regarding mutating and constraining tables.

•	The statements of a row trigger cannot read from or modify a mutating table of the triggering statement. This restriction prevents a row trigger from seeing an inconsistent set of data.

•	The statements of a row trigger cannot change the PRIMARY, FOREIGN, or UNIQUE KEY columns of a constraining table of the triggering statement. This restriction prevents order- and index-dependent success and failure of statements within a row trigger's body.

There is an exception to this restriction; a BEFORE ROW trigger fired by a single row INSERT to a table with a foreign key can modify any columns of the primary table, as long as this modification does not violate any of the integrity constraints.

Figure 8 - 1 illustrates the restriction placed on mutating tables.

Notice that the SQL statement is executed for the first row of the table and then an AFTER ROW trigger is fired. In turn, a statement in the AFTER ROW trigger body attempts to query the original table. However, because the EMP table is mutating, this query is not allowed by ORACLE. If attempted, a runtime error occurs, the effects of the trigger body and triggering statement are rolled back, and control is returned to the user or application.

If you need to update a mutating or constraining table, you might be able to use a temporary table, a PL/SQL table, or a package variable to bypass these restrictions.

Declarative integrity constraints are checked at various times with respect to row triggers; see the ORACLE7 Server Concepts Manual for information about the interaction of triggers and integrity constraints.

 Privileges Required to Create Triggers

To create a trigger in your schema, you must have the CREATE TRIGGER system privilege, and either:

•	own the table specified 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 user's 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 user's table.

 Privileges for Referenced Schema Objects in the Trigger Body

Similar to stored procedures, the object privileges to the schema objects referenced in the trigger body must be granted to the trigger's owner explicitly (not via a role). The statements in the trigger body operate under the privilege domain of the trigger's owner, not the privilege domain of the user issuing the triggering statement.

________________________________________

Debugging Triggers

Triggers can be debugged using the same facilities available for procedures and packages; see "Debugging Procedures and Packages" on page 7 - 14.

________________________________________

Altering Triggers

A trigger cannot be explicitly altered; it must be replaced with a new definition of the trigger. If you used a text editor to create your triggers, you can simply edit the corresponding text file and execute the CREATE TRIGGER statement to define the new version of the code.

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 and recreated. However, all grants made for the dropped trigger are also dropped and must be granted again when the new version of the trigger is created.

________________________________________

Dropping Triggers

Use the DROP TRIGGER command to drop a trigger from the database. For example, to drop the trigger named REORDER, enter the following statement:

DROP TRIGGER reorder;

Privileges Required to Drop Triggers

Todrop a trigger, the trigger must be in your schema or you must have the DROP ANY TRIGGER system privilege.

________________________________________

Enabling and Disabling Triggers

A trigger can be in one of two distinct modes:

enabled	An enabled trigger executes its trigger body if a triggering statement is issued and the trigger restriction (if any) evaluates to TRUE.

disabled	A disabled trigger does not execute its trigger body, even if a triggering statement is issued and the trigger restriction (if any) evaluates to TRUE.

Disabling Triggers

You might temporarily disable a trigger if:

•	An object it references is not available.

•	You have to perform a large data load and want it to proceed quickly without firing triggers.

•	You are reloading data.

By default, triggers are enabled when first created. Disable a trigger using the ALTER TRIGGER command 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 command with the DISABLE clause and the ALL TRIGGERS option. For example, to disable all triggers defined for the INVENTORY table, enter the following statement:

ALTER TABLE inventory

    DISABLE ALL TRIGGERS;

Enabling Triggers

By default, a trigger is automatically enabled when it is created; however, it can later be disabled. Once you have completed the task that required the trigger to be disabled, re-enable the trigger so it fires when appropriate.

Enable a disabled trigger using the ALTER TRIGGER command 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 defined for a specific table can be enabled with one statement using the ALTER TABLE command with the ENABLE clause with the ALL TRIGGERS option. For example, to enable all triggers defined for the INVENTORY table, enter the following statement:

ALTER TABLE inventory

    ENABLE ALL TRIGGERS;

Privileges Required to Enable and Disable Triggers

To enable or disable triggers using the ALTER TABLE command, you must either own the table, have the ALTER object privilege for the table, or have the ALTER ANY TABLE system privilege. To enable or disable triggers using the ALTER TRIGGER command, you must own the trigger or have the ALTER ANY TRIGGER system privilege.

________________________________________

Listing Information About Triggers

The following data dictionary views reveal information about triggers:

•	USER_TRIGGERS

•	ALL_TRIGGERS

•	DBA_TRIGGERS

Appendix D gives a complete description of these data dictionary views. For example, assume the following statement was used to create the REORDER trigger:

CREATE 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 type, triggering_statement, table_name

   FROM user_triggers

   WHERE name = 'REORDER';

TYPE             TRIGGERING_STATEMENT       TABLE_NAME

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

AFTER EACH ROW   UPDATE                     INVENTORY

SELECT trigger_body

   FROM user_triggers

   WHERE 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;

________________________________________

Examples of Trigger Applications

You can use triggers in a number of ways to customize information management in an ORACLE database. For example, triggers are commonly used to:

•	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

•	maintain synchronous table replicates

This section provides an example of each of the above trigger applications. These examples are not meant to be used as is, but are provided to assist you in designing your own triggers.

Auditing with Triggers

Triggers are commonly used to supplement the built-in auditing features of ORACLE. Although triggers can be written to record information similar to that recorded by the AUDIT command, triggers should be used only when more detailed audit information is required. For example, use triggers to provide value-based auditing on a per-row basis for tables.

Sometimes, the ORACLE AUDIT command is considered a security audit facility, while triggers can provide financial audit facility.

When deciding whether to create a trigger to audit database activity, consider what ORACLE's auditing features provide, compared to auditing defined by triggers.

DML as well as DDL auditing	Standard auditing options permit auditing of DML and DDL statements regarding all types of schema objects and structures. Comparatively, triggers only permit auditing of DML statements issued against tables.

Centralized audit trail	All database audit information is recorded centrally and automatically using the auditing features of ORACLE.

Declarative method	Auditing features enabled using the standard ORACLE features are easier to declare and maintain, and less prone to errors when compared to auditing functions defined by triggers.

Auditing options can be audited	Any changes to existing auditing options can also be audited to guard against malicious database activity.

Session and execution time auditing	Using the database auditing features, records can be generated once every time an audited statement is issued (BY ACCESS) or once for every session that issues an audited statement (BY SESSION). Triggers cannot audit by session; an audit record is generated each time a trigger-audited table is referenced.

Auditing of unsuccessful data access	Database auditing can be set to audit when unsuccessful data access occurs. However, any audit information generated by a trigger is rolled back if the triggering statement is rolled back.

Sessions can be audited	Connections and disconnections, as well as session activity (physical I/Os, logical I/Os, deadlocks, etc.), 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.

When to use AFTER row vs. AFTER statement triggers depends on the information being audited. For example, row triggers provide value-based auditing on a per-row basis for tables. 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 modifications to the EMP table on a per-row basis. It requires that a "reason code" be stored in a global package variable before the update.

Example	This trigger demonstrates:

•	how triggers can be used to provide value-based auditing

•	how to use public package variables

Comments within the code explain the functionality of the trigger.

CREATE TRIGGER audit_employee

AFTER INSERT OR DELETE OR UPDATE ON emp

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 pre-defined auditing

   table named AUDIT_EMPLOYEE containing the existing

   and new values of the EMP 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.name, :old.job_classification, :old.sal,

   :new.ssn, :new.name, :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 executed.

CREATE TRIGGER audit_employee_reset

AFTER INSERT OR DELETE OR UPDATE ON emp

BEGIN

   auditpackage.set_reason(NULL);

END;

Notice that the previous two triggers are both fired by the same type of SQL statement. However, the AFTER row trigger is fired once for each row of the table affected by the triggering statement, while the AFTER statement trigger is fired only once after the triggering statement execution is completed.

Another example of using triggers to do auditing is shown below. This trigger tracks changes being made to the EMP table, and stores this information in AUDIT_TABLE and AUDIT_TABLE_VALUES.

CREATE OR REPLACE TRIGGER audit_emp

   AFTER INSERT OR UPDATE OR DELETE ON emp

   FOR EACH ROW

   DECLARE

      time_now DATE;

      terminal CHAR(10);

   BEGIN

      time_now := SYSDATE;        -- get current time, and

      terminal := USERENV("TERMINAL');  -- the terminal of

                                        --    the user

      IF INSERTING THEN -- record new employee primary key

         INSERT INTO audit_table

            VALUES (audit_seq.NEXTVAL, user, time_now,

               terminal, 'EMP', 'INSERT', :new.empno);

      ELSEIF DELETING THEN  -- record primary key of

                            --    deleted row

         INSERT INTO audit_table

            VALUES (audit_seq.NEXTVAL, user, time_now,

               terminal, 'EMP', 'DELETE', :old.empno);

      ELSE  -- for updates, record the primary

         INSERT INTO audit_table  -- key of the row

                                  --    being updated

            VALUES (audit_seq.NEXTVAL, user, time_now,

               terminal, 'EMP', '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);

         ELSEIF UPDATING ('DEPTNO') THEN

            INSERT INTO audit_table_values

               VALUES (audit_seq.CURRVAL, 'DEPTNO',

                  :old.deptno, :new.deptno);

         END IF;

      END IF;

 END

/

Integrity Constraints and Triggers

Triggers and declarative integrity constraints can both be used to constrain data input. However, triggers and integrity constraints have significant differences.

Declarative integrity constraints are statements about the database that are always true. A constraint applies to existing data in the table and any statement that manipulates the table; for more information, see Chapter 6.

Triggers constrain what a transaction can do. A trigger does not apply to data loaded before the definition 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 ORACLE's declarative integrity constraint features, triggers should only be used to enforce complex business rules that cannot be defined using standard integrity constraints. The declarative integrity constraint features provided with ORACLE offer the following advantages when compared to constraints defined by triggers:

Centralized integrity checks	All points of data access must adhere to the global set of rules defined by the integrity constraints corresponding to each schema object.

Declarative method	Constraints defined using the standard integrity constraint features are much easier to write and are less prone to errors when compared with comparable constraints defined by triggers.

While most aspects of data integrity can be defined and enforced using declarative integrity constraints, triggers can be used to enforce complex business constraints not definable using declarative integrity constraints. For example, triggers can be used to enforce:

•	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 definable using the expressions allowed in a CHECK constraint

 Enforcing Referential Integrity Using Triggers

Many cases of referential integrity can be enforced using triggers. However, only use triggers when you want to enforce the UPDATE and DELETE SET NULL, and UPDATE and DELETE SET DEFAULT referential actions or when you want to enforce referential integrity between parent and child tables on different nodes of a distributed database.

When using triggers to maintain referential integrity, declare the PRIMARY (or UNIQUE) KEY constraint in the parent table. If referential integrity is being maintained between a parent and child table in the same database, you can also declare the foreign key in the child table, but disable it; this prevents the corresponding PRIMARY KEY constraint from being dropped (unless the PRIMARY KEY constraint is explicitly dropped with the CASCADE option).

To maintain referential integrity using triggers:

•	A trigger must be defined 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 defined 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 and DEPT 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 example below allows this trigger to be used in conjunction with the UPDATE_SET_DEFAULT and UPDATE_CASCADE triggers. This exception can be removed if this trigger is used alone.

CREATE TRIGGER emp_dept_check

BEFORE INSERT OR UPDATE OF deptno ON emp

FOR EACH ROW WHEN (new.deptno IS NOT NULL)

/* Before a row is inserted, or DEPTNO is updated in the EMP

   table, fire this trigger to verify that the new foreign

   key value (DEPTNO) is present in the DEPT 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 key's row so it can't be

   deleted by another transaction until this

   transaction is committed or rolled back.  */

CURSOR dummy_cursor (dn NUMBER) IS

   SELECT deptno

   FROM dept

   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;

EXCEPTION

   WHEN invalid_department THEN

      raise_application_error(-20000, 'Invalid Department'

         || ' Number' || TO_CHAR(:new.deptno)):

      CLOSE dummy_cursor;

   WHEN valid_department THEN

      CLOSE dummy_cursor;

   WHEN mutating_table THEN

      NULL;

END;

UPDATE and DELETE RESTRICT Trigger for the Parent Table     The following trigger is defined on the DEPT table to enforce the UPDATE and DELETE RESTRICT referential action on the primary key of the DEPT table:

CREATE TRIGGER dept_restrict

AFTER DELETE OR UPDATE OF deptno ON dept

FOR EACH ROW

/*  Before a row is deleted from DEPT or the primary key

   (DEPTNO) of DEPT is updated, check for dependent

   foreign key values in EMP; rollback if any arefound. */

DECLARE

   dummy INTEGER;  /* used for cursor fetch below */

   employees_present EXCEPTION;

   employees_not_present EXCEPTION;

/* Cursor used check for dependent foreign key values. */

   CURSOR dummy_cursor (dn NUMBER) IS

      SELECT deptnoFROM emp 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 notfound, close cursor

   before allowing triggeringstatement to complete. */

   IF dummy_cursor%FOUND THEN

      RAISE employees_present; /* dependent rows exist */

   ELSE

      RAISE employees_not_present; /* no dependent rows */

   END IF;

EXCEPTION

   WHEN employees_present THEN

      raise_application_error(-20001, 'Employees Present in'

         || ' Department ' || TO_CHAR(:old.deptno));

      CLOSE dummy_cursor;

   WHEN employees_not_present THEN

      CLOSE dummy_cursor;

END;

Note: This trigger will not work with self-referential tables (that is, tables with both the primary/unique key and the foreign key).

Also, this trigger does not allow triggers to cycle (such as, A fires B fires A).

UPDATE and DELETE SET NULL Triggers for Parent Table     The following trigger is defined on the DEPT table to enforce the UPDATE and DELETE SET NULL referential action on the primary key of the DEPT table:

CREATE TRIGGER dept_set_null

AFTER DELETE OR UPDATE OF deptno ON dept

FOR EACH ROW

/* Before a row is deleted from DEPT or the primary key

   (DEPTNO) of DEPT is updated, set all corresponding

   dependent foreign key values in EMP to NULL. */

BEGIN

   IF UPDATING AND :OLD.deptno != :NEW.deptno THEN

      UPDATE empSET emp.deptno = NULL

         WHERE emp.deptno = :old.deptno;

   END IF;

END;

DELETE Cascade Trigger for Parent Table     The following trigger on the DEPT table enforces the DELETECASCADE referential action on the primary key of the DEPT table:

CREATE TRIGGER dept_del_cascade

AFTER DELETE ON dept

FOR EACH ROW

/* Before a row is deleted from DEPT, delete all

   rows from the EMP table whose DEPTNO is the same as

   the DEPTNO being deleted from the DEPT table. */

BEGIN

   DELETE FROM emp

      WHERE emp.deptno = :old.deptno;

END;

Note: Typically, the code for DELETE cascade is combined with the code for UPDATE SET NULL or UPDATE SET DEFAULT to account for both updates and deletes.

UPDATE Cascade Trigger for Parent Table     The following trigger ensures that if a department number is updated in the DEPT table, this change is propagated to dependent foreign keys in the EMP 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 PACKAGE integritypackage AS

   updateseq NUMBER;

END integritypackage;

CREATE or replace PACKAGE BODY integritypackage AS

END integritypackage;

ALTER TABLE emp ADD update_id NUMBER; /* create flag col. */

CREATE TRIGGER dept_cascade1 BEFORE UPDATE OF deptno ON dept

DECLARE

   dummy NUMBER;

/* Before updating the DEPT 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 TRIGGER dept_cascade2 AFTER DELETE OR UPDATE

   OF deptno ON dept FOR EACH ROW

/* For each department number in DEPT that is updated,

   cascade the update to dependent foreign keys in the

   EMP table.  Only cascade the update if the child row

   has not already been updated by this trigger. */

BEGIN

   IF UPDATING THEN

      UPDATE emp

         SET deptno = :new.deptno,

         update_id = integritypackage.updateseq /*from 1st*/

         WHERE emp.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, delete all

      rows from the EMP table whose DEPTNO is the same as

      the DEPTNO being deleted from the DEPT table. */

      DELETE FROM emp

      WHERE emp.deptno = :old.deptno;

   END IF;

END;

CREATE TRIGGER dept_cascade3 AFTER UPDATE OF deptno ON dept

BEGIN  UPDATE emp

   SET update_id = NULL

   WHERE update_id = integritypackage.updateseq;

END;

Note: Because this trigger updates the EMP table, the EMP_DEPT_CHECK trigger, if enabled, is also fired. 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 will always work properly in your environment.

 Enforcing Complex

Check Constraints Triggers can enforce integrity rules other than referential integrity. For example, this trigger performs a complex check before allowing the triggering statement to execute. Comments within the code explain the functionality of the trigger.

CREATE TRIGGER salary_check

BEFORE INSERT OR UPDATE OF sal, job_classification ON emp

FOR EACH ROW

DECLARE

   minsal                NUMBER;

   maxsal                NUMBER;

   salary_out_of_range   EXCEPTION;

BEGIN

/* Retrieve the minimum and maximum salary for the

   employee's new job classification from the SALGRADE

   table into MINSAL and MAXSAL. */

SELECT minsal, maxsal INTO minsal, maxsal FROM salgrade

   WHERE job_classification = :new.job_classification;

/* If the employee's new salary is less than or greater

   than the job classification's 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_classification

         ||' for employee '||:new.name);

   WHEN NO_DATA_FOUND THEN

      raise_application_error(-20322,

         'Invalid Job Classification '

         ||:new.job_classification);

END;

Complex Security Authorizations and Triggers

Triggers are commonly used to enforce complex security authorizations for table data. Only use triggers to enforce complex security authorizations that cannot be defined using the database security features provided with ORACLE. For example, a trigger can prohibit updates to salary data of the EMP table during weekends, holidays, and non-working hours.

When using a trigger to enforce a complex security authorization, it is best to use a BEFORE statement trigger. Using a BEFORE statement trigger has these benefits:

•	The security check is done before the triggering statement is allowed to execute 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	 This example shows a trigger used to enforce security. The comments within the code explain the functionality of the trigger.

CREATE TRIGGER emp_permit_changes

BEFORE INSERT OR DELETE OR UPDATE ON emp

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 table during non-working hours');

END;

Transparent Event Logging and Triggers

Triggers are very useful when you want to transparently perform a related change in the database following certain events.

Example	The REORDER trigger example on page 8 - 13 shows a trigger that reorders parts as necessary when certain conditions are met (that is, a triggering statement is issued and the PARTS_ON_HAND value is less than the REORDER_POINT value).

Derived Column Values and Triggers

Triggers can derive column values automatically based upon a value provided by an INSERT or UPDATE statement. This type of trigger is useful to force values in specific columns that depend on the values of other columns in the same row. BEFORE row triggers are necessary to complete this type of operation because:

•	The dependant values must be derived before the insert or update occurs so that the triggering statement can use the derived values.

The trigger must fire for each row affected by the triggering INSERT or UPDATE statement.

Example	 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. Comments within the code explain its functionality.

BEFORE INSERT OR UPDATE OF ename ON emp

/* 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;

Synchronously Maintaining Replicate Tables with Triggers

Triggers can be used to synchronously maintain replicate tables located on different nodes of a distributed database. For an example of such a trigger, see Chapter 12 "Managing Snapshots."


CHAPTER 9. MANAGING DEPENDENCIES AMONG SCHEMA OBJECTS

The definitions of certain objects, such as views and procedures, reference other objects, such as tables. Therefore, some objects are dependent upon the objects referenced in their definitions. The following chapter discusses how to manage the dependencies among objects. Topics include:

•	using packages to minimize dependency checks

•	forcing the compilation of invalid views, procedures, packages, and triggers

•	listing dependency management information

The information on stored procedures and packages in this chapter applies only to those systems using ORACLE with the procedural option. If using Trusted ORACLE, also see the Trusted ORACLE7 Server Administrator's Guide for information about handling dependencies in Trusted ORACLE.

________________________________________

Dependency Issues

When you create a stored procedure or function, ORACLE verifies that the operations it performs are possible based on the schema objects accessed. For example, if a stored procedure contains a SELECT statement that selects columns from a table, ORACLE verifies that the table exists and contains the specified columns. If the table is subsequently redefined so that one of its columns does not exist, the stored procedure may not work properly. For this reason, the stored procedure is said to depend on the table.

In cases such as this, ORACLE automatically manages dependencies among schema objects. After a schema object is redefined, ORACLE automatically recompiles all stored procedures and functions in your database that depend on the redefined object the next time they are called. This recompilation allows ORACLE to verify that the procedures and functions can still execute properly based on the newly-defined object.

Avoiding Runtime Recompilation

Avoid runtime recompilation of stored procedures, functions, and packages. Runtime recompilation not only reduces runtime performance, but the resulting runtime compilation errors can halt the use of your applications. Follow these measures to avoid runtime recompilation:

•	Do not redefine schema objects (such as tables, views, and stored procedures and functions) while your production applications are running. Redefining objects causes ORACLE to recompile stored procedures and functions that depend on them.

•	After redefining a schema object, manually recompile dependent procedures, functions, and packages. This measure not only eliminates the performance impact of runtime recompilation, but it also notifies you immediately of compilation errors, allowing you to fix them.

You can manually recompile a procedure, stored function, or package with the COMPILE option of the ALTER PROCEDURE, ALTER FUNCTION, or ALTER PACKAGE command. For more information on these commands, see the ORACLE 7 Server SQL Language Reference Manual

You can determine the dependencies among the schema objects in your database by running the SQL script UTLDTREE.SQL.The exact name and location of this script may vary depending on your operating system. See this script for more information on how to use it.

•	Store procedures and functions in packages whenever possible. If a procedure or function is stored in a package, you can modify its definition without causing ORACLE to recompile other procedures and functions that call it.

There are several dependency issues to consider before dropping a procedure or package. Additional information about dependency issues is included in the ORACLE7 Server Concepts Manual. Some guidelines for managing dependencies follow.

Use Packages Whenever Possible     Packages are the most effective way of preventing unnecessary dependency checks from being performed. The following example illustrates this benefit.

Assume the following situation:

•	The stand-alone procedure PROC depends on a packaged procedure PACK_PROC.

•	The PACK_PROC procedure's definition is altered by recompilation of the package body.

•	The PACK_PROC procedure's specification is not altered in the package specification.

Even though the package's body is recompiled, the stand-alone procedure PROC that depends on the packaged procedure PACK_PROC is not invalidated, because the package's specification is not altered.

This technique is especially useful in distributed environments. If procedures are always part of a package, remote procedures that depend on packaged procedures are never invalidated unless a package specification is replaced or invalidated.

Whenever you recompile a procedure, you should consult with any other database administrators and application developers to identify any remote, dependent procedures and ensure that they are also recompiled. This eliminates recompilations at runtime and allows you to detect any compile-time errors that would otherwise be seen by the application user; see "Manually Recompiling Invalid Views, Procedures, Packages, and Triggers" on page 9 - 4 for more information.

The %TYPE and %ROWTYPE Attributes  The %TYPE attribute provides the datatype of a variable, constant, or column. This attribute is particularly useful when declaring a variable or procedure argument that refers to a column in a database table. The %ROWTYPE attribute is useful if you want to declare a variable to be a record that has the same structure as a row in a table or view, or a row that is returned by a fetch from a cursor.

Declaring constructs using %TYPE and %ROWTYPE attributes has the following advantages and disadvantages:

•	You do not need to know the datatype of a column or structure of a table. For example, the argument list of a procedure that inserts a row into the EMP table could be declared as:

CREATE PROCEDURE hire_fire(emp_record emp%ROWTYPE) AS ... END;

If you change the column or table structure, the constructs defined on their datatypes or structure automatically change accordingly.

•	If you define a construct using object%TYPE or object%ROWTYPE, the construct depends on object. If object is altered, the constructs that depend on object are invalidated.

In summary, while one type of dependency is eliminated using %TYPE or %ROWTYPE, another is created.

________________________________________

Manually Recompiling Invalid Views, Procedures, Packages, and Triggers

ORACLE dynamically (automatically) recompiles an invalid view or PL/SQL program unit the next time it is used. Alternatively, you can force the compilation of an invalid view or program unit using the appropriate SQL command with the COMPILE parameter.

Forced compilations are most often used to test for errors when it is known that a dependent view or program unit is invalid, but is not currently being used; therefore, automatic recompilation would not otherwise occur until the view or program unit is executed.

Invalid dependent objects can be identified by querying the data dictionary views USER_/ALL_/DBA_OBJECTS; see "Listing Dependency Management Information," on page 9 - 5, for examples.

Manually Recompiling Views

To recompile a view, use the ALTER VIEW command with the COMPILE parameter. The following statement recompiles the view EMP_DEPT contained in your schema:

ALTER VIEW emp_dept COMPILE;

 Privileges Required to Recompile a View

To manually recompile a view, the view must be contained in your schema or you must have the ALTER ANY TABLE system privilege.

Manually Recompiling Procedures and Functions

To recompile a procedure or function (stand-alone), use the ALTER PROCEDURE/FUNCTION command with the COMPILE parameter. For example, the following statement recompiles the stored procedure UPDATE_SALARY contained in your schema:

ALTER PROCEDURE update_salary COMPILE;

Manually Recompiling Packages

To recompile either a package body or both a package specification and body, use the ALTER PACKAGE command with the COMPILE parameter. For example, the following statements recompile just the body and the body and specification of the package ACCT_MGMT_PACKAGE, respectively:

ALTER PACKAGE acct_mgmt_package COMPILE BODY;

ALTER PACKAGE acct_mgmt_package COMPILE PACKAGE;

All packages, procedures and functions can be recompiled using the following syntax. The objects are compiled in dependency order, enabling each to be compiled only once.

EXECUTE DBMS_UTILITY.COMPILE_ALL;

 Privileges Required to Recompile a Procedure or Package

To manually recompile a procedure or package, the procedure or package must be contained in your schema or you must have the ALTER ANY PROCEDURE system privilege.

Manually Recompiling Triggers

An existing trigger, enabled or disabled, can be manually recompiled using the ALTER TRIGGER command. For example, to force the compilation of the trigger named REORDER, enter the following statement:

ALTER TRIGGER reorder COMPILE;

 Privileges Required to Recompile a Trigger

To recompile a trigger, you must own the trigger or have the ALTER ANY TRIGGER system privilege.

________________________________________

Listing Dependency Management Information

The following data dictionary views list information about direct dependencies and dependency management:

•	USER_\ALL_\DBA_DEPENDENCIES

•	USER_\ALL_\DBA_OBJECTS

Note: For a complete description of these data dictionary views, see Appendix D.

Consider the following statements for Examples 1 and 2:

CREATE TABLE emp . . .;

CREATE PROCEDURE hire_emp BEGIN . . . END;

ALTER TABLE emp . . . ;

Example 1

Listing the Status of an Object	The ALL_OBJECTS data dictionary view lists information about all the objects available to the current user and the current status (that is, valid or invalid) of each object. For example, the following query lists the names, types, and current status of all objects available to the current user:

SELECT object_name, object_type, status

   FROM all_objects;

The following results might be returned:

OBJECT_NAME     OBJECT_TYPE     STATUS

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

EMP             TABLE           VALID

HIRE_EMP        PROCEDURE       INVALID

Example 2

Listing Dependencies	The DBA_DEPENDENCIES data dictionary view lists all dependent objects in the database and the objects on which they directly depend. For example, the following query lists all the dependent objects in JWARD's schema:

SELECT name, type, referenced_name, referenced_type

   FROM sys.dba_dependencies

   WHERE owner = 'JWARD';

If JWARD issued the example statements at the beginning of this section, the following results might be returned:

NAME        TYPE         REFERENCED_NAME     REFERENCED_TYPE

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

HIRE_EMP    PROCEDURE    EMP                 TABLE

The Dependency Tracking Utility

The USER_\ALL_\DBA_DEPENDENCIES data dictionary views provide information about only the direct dependencies of objects. As a supplement, you can use a special dependency tracking utility to list both direct and indirect dependents of an object.

To create the dependency tracking utility, you must run the SQL script UTLDTREE.SQL. The location of this file is operating system dependent. The UTLDTREE.SQL script creates the following schema objects:

Table

DEPTREE_TEMPTAB	Structure:	object_id NUMBER

referenced_object_id NUMBER

nest_level NUMBER

seq# NUMBER

A temporary table used to store dependency information returned by the DEPTREE_FILL procedure.

View DEPTREE	Column names:	nested_level, object_type, owner, object_name, seq#

A view that lists dependency information in the DEPTREE_TEMPTAB table. The parent object is listed with a NESTED_LEVEL of 0, and dependent objects are listed with a nested level greater than 0.

View IDEPTREE	Column name:	dependencies

A view that lists dependency information in the DEPTREE_TEMPTAB table. Output is in a graphical format, with dependent objects indented from the objects on which they depend.

Sequence DEPTREE_SEQ	A sequence used to uniquely identify sets of dependency information stored in the DEPTREE_TEMPTAB.

Procedure DEPTREE_FILL	Syntax:	DEPTREE_FILL(object_type CHAR, object_owner CHAR, object_name CHAR)

A procedure that first clears the DEPTREE_TEMPTAB table in the executor's schema, then fills the same table to indicate the objects that directly or indirectly depend on (that is, reference) the specified object. All objects that recursively reference the specified object are listed, assuming the user has permission to know of their existence.

 Using UTLDTREE While Connected as INTERNAL

If you run the UTLDTREE.SQL script and use the utility while connected as INTERNAL, dependency information is gathered and displayed not only for dependent objects, but also for dependent cursors (shared SQL areas).

Example	 These SQL statements show how the UTLDTREE utility can be used to track dependencies of an object. Assume the following SQL statements:

CONNECT scott/tiger;

CREATE TABLE scott.emp ( .... );

CREATE SEQUENCE scott.emp_sequence;

CREATE VIEW scott.sales_employees AS

   SELECT * FROM scott.emp WHERE deptno = 10;

CREATE PROCEDURE scott.hire_salesperson (name VARCHAR2,

   job VARCHAR2, mgr NUMBER, hiredate DATE, sal NUMBER,

   comm NUMBER)

IS

BEGIN

   INSERT INTO scott.sales_employees

      VALUES (scott.emp_sequence.NEXTVAL, name, job, mgr,

         hiredate, sal, comm, 10;

END;

CREATE PROCEDURE scott.fire_salesperson (emp_id NUMBER) IS

BEGIN

   DELETE FROM scott.sales_employees WHERE empno = emp_id;

END;

SELECT * FROM scott.emp;

SELECT * FROM scott.sales_employees;

EXECUTE scott.hire_salesperson ('ARNALL', 'MANAGER', 7839, /

                                 SYSDATE, 1000, 500);

EXECUTE scott.fire_salesperson (7934);

Assume that before SCOTT alters the EMP table, he would like to know all the dependent objects that will be invalidated as a result of altering the EMP table. The following procedure execution fills the DEPTREE_TEMPTAB table with dependency information regarding the EMP table (executed using SQL*DBA):

EXECUTE deptree_fill('TABLE', 'SCOTT', 'EMP');

The following two queries show the previously collected dependency information for the EMP table:

SELECT * FROM deptree;

NESTED_LEV TYPE       OWNER          NAME               SEQ#

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

         0 TABLE      SCOTT          EMP                   0

         1 VIEW       SCOTT          SALES_EMPLOYEES       1

         2 PROCEDURE  SCOTT          FIRE_SALESPERSON      2

         2 PROCEDURE  SCOTT          HIRE_SALESPERSON      3

SELECT * FROM ideptree;

DEPENDENCIES

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

TABLE SCOTT.EMP

VIEW SCOTT.SALES_EMPLOYEES

PROCEDURE SCOTT.FIRE_SALESPERSON

PROCEDURE SCOTT.HIRE_SALESPERSON

Alternatively, you can reveal all of the cursors that depend on the EMP table (dependent shared SQL areas currently in the shared pool) using the UTLDTREE utility. After connecting as INTERNAL and collecting dependency information for the table SCOTT.EMP, issue the following two queries:

SELECT * FROM deptree;

NESTED_LEV TYPE   OWNER    NAME                         SEQ#

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

         0 TABLE  SCOTT    EMP                             0

         1 CURSOR <shared> "select * from scott.emp      0.5

         2 CURSOR <shared> "select * from scott.sa. . .  7.5

         3 CURSOR <shared> "BEGIN hire_salesperson. . .  9.5

         3 CURSOR <shared> "BEGIN fire_salesperson. . .  8.5

SELECT * FROM ideptree;

DEPENDENCIES

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

TABLE STEVE.EMP

   CURSOR <shared>."select * from scott.emp"

      CURSOR <shared>."select * from scott.sales_employee"

        CURSOR <shared>."BEGIN  hire_salesperson ('ARN. . .

       CURSOR <shared>."BEGIN  fire_salesperson (7934) END"


CHAPTER 10. ESTABLISHING A SECURITY POLICY

Given the many types of mechanisms available to maintain the security of an ORACLE database, a discretionary security policy should be designed and implemented to determine:

•	the level of security at the application level

•	an auditing policy

•	system and object privileges

•	database roles

•	how to grant and revoke privileges and roles

•	how to create, alter, and drop roles

•	how role use can be controlled

These topics and guidance on developing security policies are discussed in this chapter. If you are using Trusted ORACLE, see the Trusted ORACLE7 Server Administrator's Guide for additional information about establishing an overall system security policy.

________________________________________

Application Security Policy

Draft a security policy for each database application. For example, each developed database application (such as a precompiler program or SQL*Forms form) should have one or more application roles that provide different levels of security when executing the application. The application roles can be granted to user roles or directly to specific usernames.

Applications that potentially allow unrestricted SQL statement execution (such as SQL*Plus or SQL*ReportWriter) also need tight control to prevent malicious access to confidential or important schema objects.

Application Administrators

In large database systems with many database applications (such as precompiler applications or SQL*Forms applications), it may be desirable to have application administrators. An application administrator is responsible for such things as:

•	creating roles for an application and managing the privileges of each application role

•	creating and managing the objects used by a database application

•	maintaining and updating the application code and ORACLE procedures and packages, as necessary

As the application developer, you might also assume the responsibilities of the application administrator. However, these jobs might be designated to another individual familiar with the database application.

Roles and Application Privilege Management

Because most database applications involve many different privileges on many different schema objects, keeping track of which privileges are required for each application can be complex. In addition, authorizing users to run an application can involve a large number of GRANT operations. To simplify application privilege management, a role should be created and granted all the privileges required to run each application. In fact, an application might have a number of roles, each granted a specific subset of privileges that allow fewer or more capabilities while running the application.

Example	Assume that every administrative assistant uses the Vacation application to record vacation taken by members of the department. You should:

1.	Create a VACATION role.

2.	Grant all privileges required by the Vacation application to the VACATION role.

3.	Grant the VACATION role to all administrative assistants or to a role named ADMIN_ASSITS (if previously defined).

Grouping application privileges in a role aids privilege management. Consider the following administrative options:

•	You can grant the role, rather than many individual privileges, to those users who run the application. Then, as employees change jobs, only one role grant or revoke (rather than many privilege grants and revokes) is necessary.

•	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.

Enabling Application Roles

A single user can use many applications and associated roles. However, you should only allow a user to have the privileges associated with the currently running application role. For example, consider the following scenario:

•	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.

Therefore, 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. However, update modification to the INVENTORY table is not an authorized action when using the INVENTORY application, but only when using the ORDER application.

To avoid such problems, issue a SET ROLE statement at the beginning of each application to automatically enable its associated role and, consequently, disable all others. By using the SET ROLE command, each application dynamically enables particular privileges for a user only when required. A user can make use of an application's privileges only when running a given application, and is prevented from intentionally or unintentionally using them outside the context of an application.

The SET ROLE statement facilitates privilege management in that, in addition to letting you control what information a user can access, it allows you to control when a user can access it. In addition, the SET ROLE statement keeps users operating in a well-defined privilege domain, if a user gets all privileges from roles, the user cannot combine them to perform unauthorized operations; see "Enabling and Disabling Roles" on page 10 - 8 for more information.

Restricting Application Roles from Ad Hoc Tool Users

Prebuilt database applications explicitly control the potential actions of a user, including the enabling and disabling of the user's roles while using the application. Alternatively, ad hoc query tools such as SQL*Plus allow a user to submit any SQL statement (which may or may not succeed), including the enabling and disabling of any granted role. This can pose a serious security problem; without taking necessary precautions, an application user could have the ability to intentionally or unintentionally issue destructive SQL statements against database tables while using an ad hoc tool, using the privileges obtained via an application role.

For example, consider the following scenario:

•	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 table.

•	The Vacation application controls the use of the privileges obtained via the VACATION role; that is, the application controls when statements are issued.

Now consider a user who has been granted the VACATION role. However, 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 via roles, including the VACATION role. Because SQL*Plus is an ad hoc query tool, the user is not restricted to a set of predefined actions, as with designed database applications. The user can query or modify data in the EMP table as he or she chooses.

To avoid potential problems like the one above, consider the following policy for application roles:

1.	Each application should have distinct roles:

•	One role should contain all privileges necessary to use the application successfully. Depending on the situation, there might be several roles that contain more or fewer privileges to provide tighter or less restrictive security while executing the application. Each application 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 (that is, SELECT privileges for specific 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, SQL*ReportWriter, SQL*Graph, etc.; however, this role does not allow the application user to modify table data outside of the application itself. A role designed for an ad hoc query tool may or may not be protected by a password (or operating system authentication).

2.	At startup, each application should use the SET ROLE command to enable one of the application roles associated with that application. If a password is used to authorize the role, 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, 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.

3.	At termination, each application should disable the previously enabled application role.

4.	Application users should be granted application roles, as required. The administrator can prohibit a user from using application data with ad hoc tools by not granting the non-destructive role to the user.

Using this configuration, each application enables the proper role when the application is started, and disables the role when the application terminates. If an application user decides to use an ad hoc tool, the user can only enable the non-destructive role intended for that tool.

Additionally, you can:

•	Specify the roles to enable when a user starts SQL*Plus, using the PRODUCT_USER_PROFILE table. This functionality is similar to when a precompiler or OCI application issues a SET ROLE statement to enable specific roles upon application startup.

•	Disable the use of the SET ROLE command 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, such as SQL*ReportWriter, SQL*Graph, etc., 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. For more information about these features, see the appropriate tool manual.

Schemas

Each database username is said to be a schema-a security domain that can contain schema objects. The access to the database and its objects is controlled by the privileges granted to each schema.

Most schemas can be thought of as usernames-the accounts set up to allow users to connect to a database and access the database's 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 not granted the CREATE SESSION system privilege (either explicitly or via a role). However, you must temporarily grant the CREATE SESSION privilege to such schemas if you want to use the CREATE SCHEMA command to create multiple tables and views in a single transaction.

For example, the schema objects for a specific application might be owned by a 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, thereby preventing access to the associated objects via this schema. This security configuration provides another layer of protection for objects.

________________________________________

Managing Privileges and Roles

As part of designing your application, you need to determine the types of users who will be working with the application and the level of access that they must be granted to accomplish their designated tasks. You must categorize these users into role groups and then determine the privileges that must be granted to each role.

Typically, end users are granted object privileges. An object privilege allows a user to perform a particular action on a specific table, view, sequence, procedure, function, or package. Depending on the type of object, there are different types of object privileges. Table 10 - 1 summarizes the object privileges available for each type of object.

Object Privelege	   Table	    View	  Sequence	Procedure1

ALTER	      3	       3

DELETE	      3	      3

EXECUTE	       3

INDEX	      32

INSERT	      3	      3

REFERENCES	      32

SELECT	      3	     33	       3

UPDATE	      3	     3

Table 10 - 1.  Object Privileges.

1  "Procedure" refers to stand-alone stored procedures, functions, and public package constructs.

2  Privilege cannot be granted to a role.

3  Can also be granted for snapshots.

Table 10 - 2 lists the SQL statements permitted by the object privileges listed in Table 10 - 1.

As you implement and test your application, you should create each of these roles and test the usage scenario for each role to be certain that the users of your application will have proper access to the database. After completing your tests, you should coordinate with the administrator of the application to ensure that each user is assigned the proper roles.

Object Privilage	SQL Statements Permitted

ALTER	ALTER object (table or sequence)

CREATE TRIGGER ON object (tables only)

DELETE	DELETE FROM object (table or view

EXECUTE	EXECUTE object (procedure or function)

References to public package variables

INDEX	CREATE INDEX ON object (table or view)

INSERT	INSERT INTO object (table or view)

REFERENCES	CREATE or ALTER TABLE statement defining a

FOREIGN KEY integrity constraint on object (tables only)

SELECT	SELECT...FROM object (table, view, or snapshot)

SQL statements using a sequence

Table 10 - 2.  SQL Statements Permitted by Database Object Privileges.

Creating a Role

The use of a role can be protected by an associated password, as in the example below.

CREATE ROLE clerk IDENTIFIED BY bicentennial;

If you are granted a role protected by a password, you can enable or disable the role only by supplying the proper password for the role (using a SET ROLE command; see page 10 - 9 for more information). Alternatively, roles can be created so that role use is authorized using information from the operating system. For more information about use of the operating system for role authorization, see the ORACLE7 Server Administrator's Guide

If a role is created without any protection, the role can be enabled or disabled by any grantee.

Database applications usually use the role authorization feature to specifically enable an application role and disable all other roles of a user. This way, the user cannot use privileges (from a role) intended for another application. With ad hoc query tools (such as SQL*Plus or SQL*DBA), users can explicitly enable only the roles for which they are authorized (that is, they know the password or are authorized by the operating system). See page 10 - 4 for more information.

A role to be created must have a unique name among existing usernames and role names of the database. Roles are not contained in the schema of any user.

Immediately after creation, a role has no privileges associated with it. To associate privileges with a new role, the role must have privileges or other roles granted to it.

Privileges Required to Create Roles

To create a role, you must have the CREATE ROLE system privilege.

Enabling and Disabling Roles

Although a user can be granted a role, the role must be enabled before the privileges associated with it become available in the user's current session. Some, all, or none of the user's roles can be enabled or disabled. The following sections discuss when roles should be enabled and disabled and the different ways that a user can have roles enabled or disabled.

 When to Enable Roles

In general, a user's security domain should always permit the user to perform the current task at hand, yet limit the user from having unnecessary privileges for the current job. For example, a user should have all the privileges to work with the database application currently in use, but not have any privileges required for any other database applications. Having too many privileges might allow users to access information through unintended methods.

Privileges granted directly to a user are always available to the user; therefore, directly granted privileges cannot be selectively enabled and disabled depending on a user's current task. Alternatively, privileges granted to a role can be selectively made available for any user granted the role. The enabling of roles never affects privileges explicitly granted to a user. The following sections explain how a user's roles can be selectively enabled (and disabled).

Default Roles

A default role is one that is automatically enabled for a user when the user creates a session. A user's list of default roles should include those roles that correspond to his typical job function.

Each user has a list of zero, or one or more default roles. Any role directly granted to a user can potentially be a default role of the user; an indirectly granted role (a role that is granted to a role) cannot be a default role; only directly granted roles can be a default role of a user. The number of default roles for a user should not exceed the maximum number of enabled roles that are allowed per user (as specified by the initialization parameter MAX_ENABLED_ROLES); if the number of default roles for a user exceeds this maximum, errors are returned when the user attempts a connection and the user's connection is not allowed.

Note: A default role is automatically enabled for a user when the user creates a session. Placing a role in a user's list of default roles bypasses authentication for the role, whether it is authorized using a password or the operating system.

A user's list of default roles can be set and altered using the SQL command ALTER USER. If the user's list of default roles is specified as ALL, every role granted to a user is automatically added to the user's list of default roles. Only subsequent modification of a user's default role list can remove newly granted roles from a user's list of default roles.

Modifications to a user's 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.

Explicitly Enabling Roles

A user (or application) can explicitly enable a role using the SQL command SET ROLE. A SET ROLE statement enables all specified roles, provided that they have been granted to the user. All roles granted to the user that are not explicitly specified in a SET ROLE statement are disabled, including any roles previously enabled.

If a role is protected by a password, the role can only be enabled by indicating the role's password in the SET ROLE statement. If the role is not protected by a password, the role can be enabled with a simple SET ROLE statement. For example, assume that Morris' security domain is as follows:

•	He is granted three roles: PAYROLL_CLERK (password BICENTENNIAL), ACCTS_PAY (password GARFIELD), and ACCTS_REC (identified externally). The PAYROLL_CLERK role includes the indirectly granted role PAYROLL_REPORT (identified externally).

•	His only default role is PAYROLL_CLERK.

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, accts_rec;

Notice in the first statement that multiple roles can be enabled in a single SET ROLE statement. The ALL and ALL EXCEPT options of the SET ROLE command 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 command. Use this option when you want to enable most of a user's 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 command, 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, 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 via an explicit grant of another role. For example, Morris can issue the following statement:

SET ROLE payroll_report;

Privileges Required to Explicitly Enable Roles     Any user can use the SET ROLE command to enable any granted roles, provided the grantee supplies role passwords, when necessary.

 Enabling and Disabling Roles When OS_ROLES=TRUE

If OS_ROLES is set to TRUE, any role granted by the operating system can be dynamically enabled using the SET ROLE command. However, any role not identified in a user's operating system account cannot be specified in a SET ROLE statement (it is ignored), even if a role has been granted using a GRANT statement.

When OS_ROLES is set to TRUE, a user can enable as many roles as specified by the initialization parameter MAX_ENABLED_ROLES.  For more information about use of the operating system for role authorization, see the ORACLE7 Server Administrator's Guide.

Dropping Roles

When you drop a role, the security domains of all users and roles granted that role are immediately changed to reflect the absence of the dropped role's 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 via 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).

Drop a role using the SQL command DROP ROLE, as shown in the following example.

DROP ROLE clerk;

 Privileges Required to Drop Roles

To drop a role, you must have the DROP ANY ROLE system privilege or have been granted the role with the ADMIN OPTION.

Granting and Revoking Privileges and Roles

The following sections explain how to grant and revoke system privileges, roles, and object privileges.

 Granting System Privileges and Roles

System privileges and roles can be granted to other roles or users using the SQL command GRANT, as shown in the following example:

GRANT create session, accts_pay

   TO jward, finance;

Object privileges cannot be granted along with system privileges and roles in the same GRANT statement.

The ADMIN OPTION  A system privilege or role can be granted with the ADMIN OPTION. (This option is not valid when granting a role to another role.) A grantee with this option has several expanded capabilities:

•	The grantee can grant or revoke the system privilege or role to or from any user or other role in the database. (A user cannot revoke a role from himself.)

•	The grantee can further grant the system privilege or role with the ADMIN OPTION.

•	The grantee of a role can alter or drop the role.

A grantee without the ADMIN OPTION cannot perform the above operations.

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 ADMIN OPTION;

The user MICHAEL cannot only use all of the privileges implicit in the NEW_DBA role, but 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.

 Granting Object Privileges

Grant object privileges to roles or users using the SQL command GRANT. The following statement grants the SELECT, INSERT, and DELETE object privileges for all columns of the EMP table to the users JWARD and TSMITH:

GRANT select, insert, delete ON emp TO jward, tsmith;

To grant the INSERT object privilege for only the ENAME and JOB columns of the EMP table to the users JWARD and TSMITH, enter the following statement:

GRANT insert(ename, job) ON emp TO jward, tsmith;

To grant all object privileges on the SALARY view to the user WALLEN, use the ALL short cut, as in:

GRANT ALL ON salary TO wallen;

System privileges and roles cannot be granted along with object privileges in the same GRANT statement.

The GRANT OPTION     An object privilege can be granted to a user with the GRANT OPTION. This special privilege allows the grantee several expanded privileges:

•	The grantee can grant the object privilege to any user or any role in the database.

•	The grantee can also grant the object privilege to other users, with or without the GRANT OPTION.

•	If the grantee receives object privileges for a table with the GRANT OPTION and the grantee has the CREATE VIEW or the CREATE ANY VIEW system privilege, 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 object privileges with the GRANT OPTION.

Specifically note that the GRANT OPTION is not valid when granting an object privilege to a role. ORACLE prevents the propagation of object privileges via roles so that grantees of a role cannot propagate object privileges received via roles.

Privileges Required to Grant Object Privileges     To grant an object privilege, the grantor must either:

•	be the owner of the object being specified, or

•	have been granted the object privileges being granted with the GRANT OPTION

 Revoking System Privileges and Roles

System privileges and roles can be revoked using the SQL command REVOKE, as shown in the following example:

REVOKE create table, accts_rec FROM tsmith, finance;

The ADMIN OPTION for a system privilege or role cannot be selectively revoked; the privilege or role must be revoked and then the privilege or role regranted 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 does not have to be the user that originally granted the privilege or role). Additionally, any user with the GRANT ANY ROLE can revoke any role.

 Revoking Object Privileges

Object privileges can be revoked using the SQL command REVOKE. For example, assuming you are the original grantor, to revoke the SELECT and INSERT privileges on the EMP table from the users JWARD and TSMITH, enter the following statement:

REVOKE select, insert ON emp

   FROM jward, tsmith;

A grantor could also revoke all privileges on the table DEPT (even if only one privilege was granted) that he/she granted to the role HUMAN_RESOURCES by entering the following statement:

REVOKE ALL ON dept FROM human_resources;

This statement would only revoke the privileges that the grantor authorized, not the grants made by other users. The GRANT OPTION for an object privilege cannot be selectively revoked; the object privilege must be revoked and then regranted without the GRANT OPTION. A user cannot revoke object privileges from herself.

Revoking Column-Selective Object Privileges     Recall that column-specific INSERT, UPDATE, and REFERENCES privileges can be granted for tables or views; however, it is not possible to revoke column-specific privileges selectively with a similar REVOKE statement. Instead, the grantor must first revoke the object privilege for all columns of a table or view, and then selectively regrant the new column-specific privileges.

For example, assume the role HUMAN_RESOURCES has been granted the UPDATE privilege on the DEPTNO and DNAME columns of the table DEPT. To revoke the UPDATE privilege on just the DEPTNO column, enter the following two statements:

REVOKE UPDATE ON dept FROM human_resources;

GRANT UPDATE (dname) ON dept TO human_resources;

The REVOKE statement revokes the UPDATE privilege on all columns of the DEPT 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 Object Privilege     If the grantee of the REFERENCES object privilege has used the privilege to create a foreign key constraint (that currently exists), the grantor can only revoke the privilege by specifying the CASCADE CONSTRAINTS option in the REVOKE statement:

REVOKE REFERENCES ON dept FROM jward CASCADE CONSTRAINTS;

Any foreign key constraints currently defined that use the revoked REFERENCES privilege are dropped when the CASCADE CONSTRAINTS option is specified.

Privileges Required to Revoke Object Privileges     To revoke an object privilege, the revoker must be the original grantor of the object privilege being revoked.

 Cascading Effects of Revoking Privileges

Depending on the type of privilege, there may or may not be cascading effects if a privilege is revoked. The following sections explain several cascading effects.

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:

1.	You grant the CREATE TABLE system privilege to JWARD with the WITH OPTION.

2.	JWARD creates a table.

3.	JWARD grants the CREATE TABLE system privilege to TSMITH.

4.	TSMITH creates a table.

5.	You revoke the CREATE TABLE system privilege from JWARD.

6.	JWARD's 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 that user has created any procedures, all procedures contained in the user's schema must be reauthorized before they can be used again (after the revoke).

Object Privileges     Revoking an object privilege can have several types of cascading effects that should be investigated before a REVOKE statement is issued:

•	Object definitions 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 table. If the SELECT privilege on the EMP table is revoked from the owner of the TEST procedure, the procedure can no longer be executed successfully.

•	Object definitions 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 else's table, the index continues to exist after the privilege is revoked.

•	When a REFERENCES privilege for a table is revoked from a user, any foreign key integrity constraints defined 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 table and creates a foreign key on the DEPTNO column in the EMP table that references the DEPTNO column. If the REFERENCES privilege on the DEPTNO column of the DEPT table is revoked, the foreign key constraint on the DEPTNO column of the EMP table is dropped in the same operation.

•	The object privilege grants propagated using the GRANT OPTION are revoked if a grantor's object privilege is revoked. For example, assume that USER1 is granted the SELECT object privilege with the GRANT OPTION, and grants the SELECT privilege on EMP to USER2. Subsequently, the SELECT privilege is revoked from USER1. This revoke is cascaded to USER2 as well. Any objects that depended on USER1's and USER2's revoked SELECT privilege can also be affected.

Granting to, and Revoking from, the User Group PUBLIC

Privileges and roles can also be granted to and revoked from the user group PUBLIC. Because PUBLIC is accessible to every database user, all privileges and roles granted to PUBLIC are accessible to every database user.

You should only grant a privilege or role to PUBLIC if every database user requires the privilege or role. This recommendation restates the general rule that at any given time, each database user should only have the privileges required to successfully accomplish the current task.

Revokes from PUBLIC can cause significant cascading effects, depending on the privilege that is revoked. If any privilege related to a DML operation is revoked from PUBLIC (for example, SELECT ANY TABLE, UPDATE ON emp), all procedures in the database (including functions and packages) must be reauthorized before they can be used again. Therefore, use caution when granting DML-related privileges to PUBLIC.

When Do Grants and Revokes Take Effect?

Depending upon what is granted or revoked, a grant or revoke takes effect at different times:

•	All grants/revokes of privileges (system and object) to anything (users, roles, and PUBLIC) are immediately observed.

•	All grants/revokes of roles to anything (users, other roles, PUBLIC) are only observed 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.


CHAPTER 11. DESIGNING DISTRIBUTED APPLICATIONS

This chapter describes the special considerations that are necessary if you are designing an application to run on a distributed database. The ORACLE7 Server Concepts Manual describes how ORACLE eliminates much of the need to design applications specifically to work in a distributed environment. The location of data is transparent to the user as well as the application; however, you will need to think about:

•	where this data should be located for fast access

•	how to name objects uniquely throughout the database

•	how to control connections via database links

•	how to design distributed queries

The information in this chapter applies only to those systems using ORACLE with the distributed option. Table snapshots, which are often used in distributed databases, are discussed in Chapter 12.

See the Trusted ORACLE7 Server Administrator's Guide for additional information about designing an application to run on a multilevel distributed database.

________________________________________

Deciding Where to Locate the Data

In a distributed database environment, you should coordinate with the database administrator to determine the best location for the data. Some issues to consider are:

•	number of transactions posted from each location

•	amount of data (portion of table) used by each node

•	performance characteristics and reliability of the network

•	speed of various nodes, capacities of disks

•	criticality of access if a node or link is down

•	need for referential integrity among tables

________________________________________

Using Snapshots to Replicate Tables on Remote Nodes

Users of the distributed option can replicate a table on other nodes in the distributed database using read-only table snapshots. Snapshots represent the contents of the master table at a given point in time and are best used for tables that are queried often from many different nodes, but are seldom modified. Snapshots allow queries to be issued against a local table, providing faster results. Snapshots also allow data to continue to be accessed at other sites, even if the master table becomes unavailable.

Snapshots are periodically refreshed, either manually or automatically at specified intervals, to reflect the current state of the master table. A fast refresh requires a snapshot log and updates only those rows that have changed since the last refresh, while a complete refresh regenerates the snapshot from the master table. See Chapter 12, "Managing Snapshots," for additional information.

________________________________________

Naming Objects

You should decide when you want to use partial and complete global object names in the definition of views, synonyms, and procedures. Keep in mind that database names should be stable and databases should not be unnecessarily moved within a network.

In a distributed database system, each database should have a unique global name. The global name is composed of the database name and the network domain that contains the database. Each object in the database then has a global object name consisting of the object name and the global database name. Because ORACLE ensures that the object name is unique within a database, you can ensure that it is unique across all databases by assigning unique global database names. You should coordinate with your database administrator on this task, as it is usually the DBA who is responsible for assigning database names. See "Name Resolution of Objects Referenced in SQL Statements," on page 2 - 34, for more information on object naming.

________________________________________

Controlling Connections Established by Database Links

When a global object name is referenced in a SQL statement or remote procedure call, database links are used to establish a connection to and session in the remote database on behalf of the local user. The remote connection and session are only created if the connection has not already been established previously for the local user session.

The connections and sessions established to remote databases persist for the duration of the local user's session, unless the application (or user) explicitly terminates them. Terminating remote connections established using database links is useful for disconnecting high cost connections (such as long distance phone connections) that are no longer required by the application.

The application developer or user can close (terminate) a remote connection and session using the ALTER SESSION command with the CLOSE DATABASE LINK parameter. For example, assume you issue the following query:

SELECT * FROM emp@sales;

COMMIT;

The following statement terminates the session in the remote database pointed to by the SALES database link:

ALTER SESSION CLOSE DATABASE LINK sales;

If partial global database names are specified, the local ORACLE expands the name using the network domain of the local database.

Note: Before closing a database link, you must first close all cursors that use the link and then end your current transaction if it uses the link.

Privileges Required to Close a Database Link Connection     To close a database link connection in your user session, you must have the ALTER SESSION system privilege.

________________________________________

Sequences in Distributed Transactions

A remote sequence can be referenced in a remote statement if both of the following conditions are met:

•	All sequences, updated tables, SELECT FOR UPDATE tables, LONG columns, and locked tables referenced in the statement are located at the same node.

•	At least one referenced table is at the same node as the sequence.

For example, the following statement would fail because the sequence and the updated table are not located on the same node:

INSERT INTO inventory

SELECT seq1.NEXTVAL@warehouse, part_desc

   FROM parts_list@warehouse

If the above example is changed, as shown below, the statement should succeed.

INSERT INTO inventory@warehouse

SELECT seq1.NEXTVAL@warehouse, part_desc

   FROM parts_list@warehouse

________________________________________

Referential Integrity in a Distributed Database

ORACLE does not permit declarative referential integrity constraints to be defined across nodes of a distributed database (that is, a declarative referential integrity constraint on one table cannot specify a foreign key that references a primary or unique key of a remote table). However, parent/child table relationships across nodes can be maintained using triggers. For more information about triggers that enforce referential integrity, refer to Chapter 8.

Note: If you decide to define referential integrity across the nodes of a distributed database using triggers, be aware that network failures can limit the accessibility of not only the parent table, but also the child table. For example, assume that the child table is in the SALES database and the parent table is in the HQ database. If the network connection between the two databases fails, some DML statements against the child table (those that insert rows into the child table or update a foreign key value in the child table) cannot proceed because the referential integrity triggers must have access to the parent table in the HQ database.

________________________________________

Distributed Queries

You can use a trigger or stored procedure to create a distributed query. This distributed query is decomposed by the local ORACLE into a corresponding number of remote queries, which are sent to the remote nodes for execution. The remote nodes execute the queries and send the results back to the local node. The local node then performs any necessary post-processing and returns the results to the user or application.

If a portion of a distributed statement fails, for example, due to an integrity constraint violation, ORACLE returns error number ORA-02055. Subsequent statements or procedure calls return error number ORA-02067 until a rollback or rollback to savepoint is issued.

You should design your application to check for any returned error messages that indicate that a portion of the distributed update has failed. If you detect a failure, you should rollback the entire transaction (or rollback to a savepoint) before allowing the application to proceed.

________________________________________

Handling Errors in Remote Procedures

When a procedure is executed locally or at a remote location, four types of exceptions can occur:

•	PL/SQL user-defined exceptions, which must be declared using the keyword EXCEPTION

•	PL/SQL pre-defined 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, one can be assigned using PRAGMA_EXCEPTION_INIT, as shown in the following example:

...

null_salary EXCEPTION;

PRAGMA EXCEPTION_INIT(null_salary, -20101);

...

RAISE_APPLICATION_ERROR(-20101, 'salary is missing');

...

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-defined 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.

________________________________________

Troubleshooting Distributed Transaction Problems

After a network or system failure occurs, it can cause the following types of problems for the users of the distributed database system:

•	A two-phase commit being processed when a failure occurs might not be completed at all nodes of the session tree.

•	If a failure persists (for example, the network is down for a long time), the data exclusively locked by in-doubt transactions is unavailable to statements of other transactions.

Failures that Interrupt a Two-Phase Commit

In general, failures will be handled by ORACLE's automatic recovery features. However, in extended outages, a database administrator might want to force the commit or rollback of a transaction to release any locked data. Thus, you should design your application to save information about a transaction if an error is encountered. If necessary, the DBA can then use this information to recover the distributed transaction manually.

The error messages issued if a problem is encountered when a user commits a distributed transaction are:

ORA-02050: transaction ID rolled back, some remote dbs may be in-doubt

ORA-02051: transaction ID committed, some remote dbs may be in-doubt

ORA-02054: transaction ID in doubt

Failures that Prevent the Access of Data

When a user issues a SQL statement, ORACLE attempts to lock the required resources to execute the statement successfully. If the requested data is being held by another uncommitted transaction, and remains locked for an excessive amount of time, a time-out can occur, and the following error message is returned:

ORA-2049: time-out: distributed transaction waiting for lock

Because no data has been modified, no actions are necessary as a result of the time-out, and your application should proceed as if a deadlock has been encountered. The time-out interval can be set using the DISTRIBUTED_LOCK_TIMEOUT initialization parameter. If the lock is the result of an in-doubt transaction, the following error message is returned:

ORA-1591: lock held by in-doubt distributed transaction ID

Once again, you should design your application to save information about the transaction, for use by the DBA, if such an error is encountered.


CHAPTER 12. MANAGING SNAPSHOTS

This chapter describes how table snapshots can be used to provide copies of tables at remote sites, without requiring the use of remote queries. Topics include:

•	the mechanisms of the table snapshot feature

•	recommendations for using snapshots

•	alternatives to table snapshots

The information in this chapter applies only to those systems using ORACLE with the distributed option.

See the Trusted ORACLE7 Server Administrator's Guide for information about additional requirements for managing snapshots in Trusted ORACLE.

________________________________________

When to Use Snapshots

Use of the table snapshot feature is appropriate under the following conditions:

•	The master table is rarely updated, yet often queried.

•	Users query the master table's data from many nodes in the distributed database system.

When deciding whether to create snapshots of a table, you should also understand the cost. Each database involved in a master table/snapshot relationship assumes additional processing overhead (to update each snapshot) and space requirements (to store each snapshot). Unnecessary use of snapshots needlessly decreases database performance and increases space usage.

________________________________________

Creating Snapshots

Create a local snapshot using the SQL command CREATE SNAPSHOT. Similar to creating tables, you can specify storage characteristics for the snapshot's data blocks, extent sizes and allocation, and the tablespace to hold the snapshot; or you can specify a cluster to hold the snapshot. Unique to snapshots, you can specify how the snapshot is to be refreshed and the distributed query that defines the snapshot. You must fully qualify any remote table names used in the defining query. For example, the following CREATE SNAPSHOT statement defines a local snapshot to replicate the remote EMP table located in the SCOTT schema in NY:

CREATE SNAPSHOT emp_sf

   PCTFREE 5 PCTUSED 60

   TABLESPACE users

   STORAGE (INITIAL 50K NEXT 50K PCTINCREASE 50)

   REFRESH FAST

           START WITH sysdate

           NEXT sysdate + 7

   AS SELECT * FROM scott.emp@ny;

Whenever a snapshot is created, it is immediately populated with the rows returned by the query that defines the snapshot. From thereafter, the snapshot is refreshed as specified by the REFRESH clause; see your ORACLE7 Server Administrator's Guide

Naming Snapshots

Snapshots are contained in a user's schema. A snapshot must have a unique name with respect to other objects contained in a user's schema (such as tables and views).

Specifying the Defining Query of a Snapshot

The defining query of a snapshot can be any valid query of tables, views, or other snapshots that are not owned by user SYS. This query cannot contain either an ORDER BY or FOR UPDATE clause. Furthermore, simple snapshots are defined using a query that does not contain GROUP BY or CONNECT BY clauses, or join, subquery, or set operations.

The query that defines a snapshot can define a snapshot with a different structure from that of the master table. For example, the following CREATE SNAPSHOT statement creates a local snapshot named EMP_DALLAS, with only the EMPNO, ENAME, and MGR columns of the master table (in New York), and only the rows of the employees in department 10:

CREATE SNAPSHOT emp_dallas

   .

   .

   .

   AS SELECT empno, ename, mgr

      FROM scott.emp@ny

      WHERE deptno = 10;

Creating a Clustered Snapshot

A snapshot can be created in a cluster, just as a table can be created in a cluster. The following statement creates a snapshot named EMP_DALLAS in the EMP_DEPT cluster:

CREATE SNAPSHOT emp_dallas

   .

   .

   .

   CLUSTER emp_dept

   .

   . ;

The storage parameters of the cluster's data segment are used for the storage of the clustered snapshot, even if storage parameters are specified for the snapshot.

Privileges Required to Create Snapshots

To create a snapshot, the following sets of privileges must be granted as follows:

•	To create a snapshot in your own schema, you must have the CREATE SNAPSHOT, CREATE TABLE, and CREATE VIEW (only for simple snapshots) system privileges as well as the appropriate SELECT privilege on the master tables.

•	To create a snapshot in another user's schema, you must have the CREATE ANY SNAPSHOT, CREATE ANY TABLE, CREATE ANY VIEW, and CREATE ANY INDEX (only for simple snapshots) system privileges as well as the appropriate SELECT privilege on the master table. Additionally, for the snapshot to be of any use, the owner of the snapshot must have the appropriate SELECT privilege on the master tables

In both of the above cases, the owner of the snapshot must also have sufficient quota on the tablespace intended to hold the snapshot.

The large set of privileges required to create a snapshot is due to the underlying objects that must also be created on behalf of the snapshot.

Creating Complex Snapshots vs. Creating Local Views

When creating a complex snapshot, consider an alternative: creating simple snapshots and performing the complex query using a view in the remote database. Figure 12 - 1 illustrates the advantages and disadvantages of completing the same operation by the two different methods.

Method A shows a complex snapshot. The snapshot in Database II exhibits efficient query performance because the join operation has already been completed during the snapshot's refresh. However, complete refreshes must be performed in this case because it is a complex snapshot.

Method B shows two simple snapshots in Database II as well as a view that performs the join in the snapshots' database. Query performance against the view would not be as good as the query performance against the complex snapshot in Method A. However, the simple snapshots can be more efficiently refreshed using snapshot logs.

In summary, to decide which method to use:

•	If you refresh rarely and want faster query performance, use Method A.

•	If you refresh regularly and can sacrifice query performance, use Method B.

________________________________________

Creating Snapshot Logs for Simple Snapshots

Creating a snapshot log decreases the amount of processing and time needed to refresh a simple snapshot. You cannot use snapshot logs with complex snapshots. A snapshot log is associated with a single master table; likewise, a master table can have only one snapshot log. If multiple simple snapshots are based on the same master table, they can all use the same snapshot log.

Snapshot logs are created in the master database using the SQL command CREATE SNAPSHOT LOG. You can set storage options for the snapshot log's data blocks, extent sizes and allocation, and tablespace to hold the snapshot log. The following statement creates a snapshot log associated with the EMP table:

CREATE SNAPSHOT LOG ON emp

   TABLESPACE users

   STORAGE (INITIAL 10K NEXT 10K PCTINCREASE 50);

Naming Snapshot Logs

The snapshot log is always created in the same schema that contains the master table. Since you cannot specify a name for the snapshot log (one is implicitly given by ORACLE), uniqueness is not a concern.

Privileges Required to Create Snapshot Logs

If you own the master table, you can create an associated snapshot log if you have the CREATE TABLE and CREATE TRIGGER system privileges. If you are creating a snapshot log for a table in another user's schema, you must have the CREATE ANY TABLE and CREATE ANY TRIGGER system privileges. In either case, the owner of the snapshot log must have sufficient quota in the tablespace intended to hold the snapshot log.

The privileges required to create a snapshot log directly relate to the privileges necessary to create the underlying objects associated with a snapshot log.

Creation Order of a Simple Snapshot and the Snapshot Log

If you are creating a simple snapshot, it is more efficient to create the snapshot log (if desired) before the snapshot. Figure 12 - 2 illustrates the two orders of creation.

Notice that by Method A, the first refresh of the snapshot cannot use the log because the log cannot reflect all updates entered between the creation of the snapshot and the creation of the snapshot log; therefore, two complete refreshes using the master table are necessary.

Alternatively, Method B only requires one complete refresh (when creating the snapshot); subsequent refreshes can immediately use the snapshot log. If the master table is large or a number of simple snapshots are based on the same master table, creating the snapshot log before the snapshots can be much more efficient.

In summary, a snapshot refresh uses a snapshot log if it existed at the time the snapshot was last refreshed.

________________________________________

Using Snapshots

Snapshots are queried just like a table or view. For example, the following statement queries a snapshot named EMP:

SELECT * FROM emp;

Because snapshots are read-only, you cannot issue any INSERT, UPDATE, or DELETE statements when using a snapshot; if you do, an error is returned. Although INSERT, UPDATE, and DELETE statements can be issued against the base table for a snapshot, they can corrupt the snapshot. Never manipulate data in the base table of a snapshot. Updates are allowed on the master table only, which must then be refreshed to update the snapshot.

Creating Views and Synonyms Based on Snapshots

Views or synonyms can be defined based on snapshots. The following statement creates a view based on the EMP snapshot:

CREATE VIEW sales_dept AS

   SELECT ename, empno

   FROM emp

   WHERE deptno = 10;

Privileges Required to Use a Snapshot

To query a snapshot, you must have the SELECT object privilege for the snapshot, either explicitly or via a role.

________________________________________

Indexing Snapshots

To increase the query performance when using a snapshot, you can create indexes for the snapshot. To index a column of a snapshot, you must create the index on the underlying "SNAP$_" table created to hold the rows of the snapshot.

________________________________________

Dropping Snapshots

You can drop a snapshot independently of the master tables or a snapshot log if you decide that you no longer want to replicate a table in a database. To drop a local snapshot, use the SQL command DROP SNAPSHOT. For example:

DROP SNAPSHOT emp;

If you drop the only snapshot of a master table, you should also drop the snapshot log of the master table, if appropriate.

Privileges Required to Drop a Snapshot

Only the owner of a snapshot, or a user with the DROP ANY SNAPSHOT, DROP ANY TABLE, and DROP ANY VIEW system privileges can drop a snapshot.

________________________________________

Dropping Snapshot Logs

You can drop a snapshot log independently of its master table or any existing snapshots. You might decide to drop a snapshot log if:

•	All simple snapshots of a master table have been dropped.

•	All simple snapshots of a master table are to be completely refreshed, not fast refreshed.

To drop a local snapshot log, use the SQL command DROP SNAPSHOT LOG, as in:

DROP SNAPSHOT LOG emp_log;

Privileges Required to Drop a Snapshot Log

Only the owner of the master table, or a user with the DROP ANY TABLE system privilege can drop a snapshot log.

________________________________________

Alternatives to Table Snapshots

If the table snapshot feature built-in to ORACLE does not meet your requirements for copying data among the nodes of a distributed database, there are two alternatives:

triggers	Triggers can be used to maintain replicate tables on multiple nodes of a distributed database. Each replicate can be updated. Updates to a replicate are automatically and synchronously (immediately) distributed to the other replicates.

manual table replication	You can manually copy a table among the nodes of a distributed database (such as using SQL or ORACLE's Import/Export utilities). Copies of a master table are only as recent as the last time the master table was copied. You could design your application to automate this process.

Deciding When to Use Snapshots vs. Triggers vs. Manual Replication

Selecting the proper method of table replication is very important. If you choose the incorrect method for your application, database performance can be hampered unnecessarily, or you can make more work for yourself.

If the table being replicated is undergoing a significant amount of updates that only need to be reflected in the other replicates periodically, manual table replication or snapshots are the best choices; using triggers with such a table would cause unnecessary performance degradation.

If the table being replicated is low update and high query, you should select either snapshots or triggers (manually copying a table is not automatic). The following sections discuss several topics to consider when deciding whether to use snapshots or triggers to replicate a specific table.

 Synchronous vs. Asynchronous Replication

If updates to a replicated table must always reflect the current state of the table, synchronous table replication using triggers should be considered. However, if the given table is rarely updated (for example, history tables), snapshots are easier to implement and just as effective as triggers.

If you decide to use asynchronous table replication (snapshots), it is likely, but not guaranteed, that multiple replicas are consistent with one another because copies must be updated one at a time.

 Network Failures Limit the Effectiveness of Triggers

If triggers are used to replicate tables, be aware that a network failure limits the site autonomy of each node involved in the table replication.

Warning: If the network is down, distributed statements in a trigger cannot execute, causing the trigger to raise an exception; unless this exception is explicitly handled by the trigger, the statements of the trigger and the triggering statement are rolled back. Therefore, neither the local nor the remote table can be updated unless the triggers involved in table replication are disabled.

Alternatively, snapshots are refreshed periodically. If the network is down when attempting a refresh, the snapshot can be refreshed at a later time. More important, the site autonomy of each node is better preserved using snapshots for table replication.

 Performance Differences

Snapshots can potentially provide better performance than triggers. Snapshots are refreshed periodically, with many updates occurring in a single operation. Alternatively, table replication using triggers forces updates to occur every time an update to a replicate occurs. Therefore, if a significant number of updates occurs, snapshot refreshes are more efficient than triggers because many updates are concentrated into one operation, which requires less network traffic and fewer two-phase commits than table replication using triggers.

 Declarative vs. Procedural Definition

Implementing table replication using snapshots is rather simple; the implementation is declarative, using SQL. Alternatively, triggers must be coded and debugged; this adds unnecessary complexity unless the application requires the characteristics triggers offer in table replication.

Snapshot Alternatives

The following sections explain each alternative to table snapshots.

 Table Replication Using Triggers

You can write triggers to implement the synchronous replication of two or more tables among different nodes of a distributed database. If implemented using triggers, table replication has the following characteristics:

•	Each copy can be queried and updated and all updates are propagated immediately to all copies. If these are primary requirements, then triggers must be used for table replication.

•	Remote updates performed by triggers are committed by the user's transaction containing the triggering UPDATE statement using a normal two-phase commit.

•	If replication triggers are disabled (for example, for bulk loads), replication operations are not applied once the triggers are re-enabled. Therefore, copies are not "copies" if replication triggers are disabled when changes are performed on one or more of the tables to be in sync.

•	If a network failure prevents communication among nodes containing replicates, neither local nor remote copies of the table can be updated until the network failure is resolved, potentially limiting the update availability of the "copied" tables.

Steps for Setting Up Table Replication Using Triggers     If you decide to use triggers to implement table replication, you need to follow these steps:

1.	The table to be copied must have a primary key.

2.	Create a flag column for each replica. A flag column, datatype CHAR(1), in each table is necessary to prevent an endless cascade of triggers being fired. For example, if you update EMP@NY, a trigger fires to update EMP@SF. However, when the trigger updates EMP@SF, you do not want to update EMP@NY again. The flag column is used to indicate which replicas have already been updated by the original triggering statement.

3.	Create local views of each table that do not reveal the presence of the flag column to end-users.

4.	Create the necessary database links in each database that holds a replicate, if not already done.

5.	Create the replication triggers on each replica. The following examples demonstrate the triggers necessary to duplicate EMP_BASE@NY and EMP_BASE@SF. For simplicity, the EMP_BASE table at each node is considered to have three columns: EMPNO, DEPTNO, and FLAG.

At New York:

CREATE TRIGGER emp_ins

   AFTER INSERT ON emp_base

   FOR EACH ROW

   WHEN (new.flag IS NULL)

   BEGIN

   -- flag is null implies user insert; forward insert to sf

   INSERT INTO fred.emp_base@sf

   VALUES(:new.empno, :new.deptno, 'T');  -- insert remote

                                          --    row

   END;

/

CREATE TRIGGER emp_upd

   AFTER UPDATE ON emp_base

   FOR EACH ROW

   BEGIN

   IF NOT updating('flag') THEN

      -- a user update; forward update to sf

      UPDATE fred.emp_base@sf SET

         empno = :new.empno,

         deptno = :new.deptno,

         flag = 'T'   -- trigger always updates flag

      WHERE empno = :old.empno;

   END IF;

   END;

/

CREATE TRIGGER emp_del

   AFTER DELETE ON emp_base

   FOR EACH ROW

   DECLARE

      mutating EXCEPTION;

      PRAGMA exception_init(mutating, -4091);

   BEGIN

   DELETE fred.emp_base@sf WHERE empno = :old.empno;

   EXCEPTION

      WHEN mutating THEN NULL;

   END;

/

At San Francisco, the same three triggers are created, with "EMP@SF" replaced by "EMP@NY."

This example allows only one row to be modified at a time. You could write a more complex trigger to allow multiple updates by saving updates in a temporary table and deferring all updates to the end of the statement execution.

 Manually Copying Tables Among Nodes of a Distributed Database

You can manually replicate tables among the nodes of a distributed database. Manual table replication is often a valid choice if the master table experiences high update activity while read-only replicas only need to periodically reflect the changes to the master table (for example, when new versions of the replicas are made every day). In this situation, the configuration involved in table replication by snapshots can be avoided. You should discuss this decision with the person who will be administering your application.


APPENDIX A. SUPPLIED PACKAGES

ORACLE is supplied with several packages that allow you to more fully take advantage of many of ORACLE's features. You might also want to review these ORACLE supplied packages for ideas in designing and implementing your own stored procedures. The procedures in these packages provide the following functionality:

•	access to selected features in SQL from PL/SQL

•	links between ORACLE Server and Oracle*Mail

•	performance improvements for short, non-distributed transactions

•	access to the ORACLE lock management services

•	ability to signal that an event has occurred in the database

•	ability to send messages between sessions

•	output from a stored procedure or trigger

The information in this appendix applies only for those systems using ORACLE with the procedural option.

________________________________________

Support for SQL Features

ORACLE is supplied with the following packaged procedures, which allow PL/SQL to access some features of SQL. These packages run as the invoking user rather than the package owner. All of these packages require the procedural extension. The packaged procedures are callable through public synonyms of the same name. The footnotes at the end of this table explain any restrictions on the use of each procedure.

Package	Procedure(Arguments)	SQL Command Equivalent

close_database_link(dblink varchar2)	ALTER SESSION CLOSE DATABASE

dblink

dbms_session

reset_package5	This procedure re-initializes the state of

all packages; there is no SQL equivalent

dbms_session

set_label(lbl varchar2)4	ALTER SESSION SET LABEL text

dbms_session

set_mls_label_format(	ALTER SESSION SET MLS_LABEL_FORMAT

       fmt varchar2)4	= fmt

dbms_session

set_nls(param varchar2, 	ALTER SESSION SET nls_param =

        value varchar2)1,4	nls_param_values

dbms_session

set_role(role_cmd varchar2)1	SET ROLE ...

dbms_session

set_sql_trace(sql_trace boolean)	ALTER SESSION SET SQL_TRACE =

[TRUE | FALSE]

dbms_session

unique_session_id 	This procedure returns a unique session

      return varchar2	ID; there is no SQL equivalent.

dbms_session

is_role_enabled 	This procedure is used to determine is a

      return boolean	role is enabled; there is no SQL

equivalent.

dbms_session

alter_compile1,2,3,4	ALTER PROCEDURE proc COMPILE

dbms_ddl

alter_compile1,2,3,4	ALTER FUNCTION func COMPILE

dbms_ddl

alter_compile1,2,3,4	ALTER PACKAGE pack COMPILE

dbms_ddl

analyze_object(type   varchar2,	ANALYZE INDEX

               owner  varchar2,

               name   varchar2,

               method varchar2)

dbms_ddl

analyze_object(type   varchar2,	ANALYZE TABLE

               owner  varchar2,

               name   varchar2,

               method varchar2)

dbms_ddl

analyze_object(type   varchar2,	ANALYZE CLUSTER

               owner  varchar2,

               name   varchar2,

               method varchar2)

dbms_ddl

compile_all1,2,3,4	This procedure is equivalent to calling

alter_compile on all procedures,

functions and packages accessible by you.

Compilation is completed in dependency

order.

dbms_utility

analyze_schema(schema varchar2,	This procedure is equivalent to calling

               method varchar2)	analyze_object on all objects in the

given schema.

dbms_utility

format_error_stack	This procedure formats the error stack

       return varchar2	into a variable.

dbms_utility

format_call_stack	This procedure formats the current call

       return varchar2	stack into a variable.

dbms_utility

is_parallel_server	This procedure returns TRUE when

       return boolean	running in Parallel Server mode.

dbms_utility

get_time	This procedure returns the time in

       return number	hundredths of a second.

dbms_utility

advise_commit	ALTER SESSION ADVISE COMMIT

dbms_transaction

advise_rollback	ALTER SESSION ADVISE ROLLBACK

dbms_transaction

advise_nothing	ALTER SESSION ADVISE NOTHING

dbms_transaction

commit1,2,4	COMMIT

dbms_transaction

commit_comment(cmnt varchar2)1,2,4	COMMIT COMMENT text

dbms_transaction

commit_force(xid     varchar2,	COMMIT FORCE text ...

             scn     varchar2

             default null)1,2,3,4

dbms_transaction

read_only1,3,4	SET TRANSACTION READ ONLY

dbms_transaction

read_write1,3,4	SET TRANSACTION READ WRITE

dbms_transaction

rollback1,2,4	ROLLBACK

dbms_transaction

rollback_force(xid varchar2)1,2,3,4	ROLLBACK ... FORCE text ...

dbms_transaction

rollback_savepoint(	ROLLBACK ... TO SAVEPOINT ...

             svpt varchar2)1,2,4

dbms_transaction

savepoint(savept varchar2)1,2,4	SAVEPOINT savepoint

dbms_transaction

use_rollback_segment(	SET TRANSACTION USE ROLLBACK

            rb_name varchar2)1,2,4	SEGMENT segment

dbms_transaction

begin_discrete_transaction1,3,4,5	See page A - 4 for more information

dbms_transaction

Table A - 1.  Supplied Packages

1not allowed in triggers

2 not allowed in procedures called from SQL*Forms

3not allowed in read-only transactions

4not allowed in remote (coordinated) sessions

5not allowed in recursive sessions

For more details on each SQL command equivalent, refer to the ORACLE7 Server SQL Language Reference Manual. The COMMIT, ROLLBACK, ROLLBACK... TO SAVEPOINT, and SAVEPOINT procedures are directly supported by PL/SQL; they are included in the package for completeness.

________________________________________

ORACLE Server Link to Oracle*Mail

ORACLE is supplied with a stored procedure that sends a message to Oracle's mail product, Oracle*Mail. Any Oracle tool that can call stored procedures can call the send mail procedure. To use the send mail procedure, you must be running Version 1 (not Version 2) of Oracle*Mail on a Version 6 or ORACLE7 database.

Requirements

There are two scripts associated with the send mail procedure: DBMSMAIL.SQL and UTLMAIL.SQL

Run DBMSMAIL.SQL against the ORACLE7 database where the send mail procedure will be called.

Run UTLMAIL.SQL against the Version 6 or ORACLE7 database where Oracle*Mail is installed.

Send Mail Procedure Syntax

The send mail procedure is part of the public package DBMS_MAIL. The syntax of the send mail procedure is as follows:

DBMS_MAIL.SEND (FROM, TO, CC, BCC, SUBJECT, REPLY_TO, BODY)

Each argument is of type VARCHAR2. See the appropriate language reference manual for details on how to pass arguments.

For a description of each argument, see the Oracle*Mail Application Programmer's Guide.

________________________________________

Discrete Transactions

You can improve the performance of short, non-distributed transactions by using the BEGIN_DISCRETE_TRANSACTION procedure. This procedure streamlines transaction processing so short transactions can execute more rapidly.

Deciding When to Use Discrete Transactions

This streamlined transaction processing is useful for transactions that:

•	modify only a few database blocks

•	seldom change an individual database block more than once per transaction

•	do not modify data likely to be requested by long-running queries

•	do not need to see the new value of data after modifying the data

•	do not modify tables containing any LONG values

In deciding to use discrete transactions, you should consider the following factors:

•	Can the transaction be designed to work within the constraints placed on discrete transactions?

•	Does using discrete transactions result in a significant performance improvement under normal usage conditions?

Discrete transactions can be used concurrently with standard transactions. Choosing whether to use discrete transactions should be a part of your normal tuning procedure. Although discrete transactions can only be used for a subset of all transactions, for sophisticated users with advanced application requirements, where speed is the most critical factor, the performance improvements can make working within the design constraints worthwhile.

How Discrete Transactions Work

During a discrete transaction, all changes made to any data are deferred until the transaction commits. Redo information is generated, but is stored in a separate location in memory.

When the transaction issues a commit request, the redo information is written to the redo log file (along with other group commits) and the changes to the database block are applied directly to the block. The block is written to the database file in the usual manner. Control is returned to the application once the commit completes. This eliminates the need to generate undo information since the block is not actually modified until the transaction is committed, and the redo information is stored in the redo log buffers.

As with other transactions, the uncommitted changes of a discrete transaction are not visible to concurrent transactions. For regular transactions, undo information is used to re-create old versions of data for queries that require a consistent view of the data. Because no undo information is generated for discrete transactions, a discrete transaction that starts and completes during a long query can cause the query to receive the "snapshot too old" error if the query requests data changed by the discrete transaction. For this reason, you might want to avoid performing queries that access a large subset of a table that is modified by frequent discrete transactions.

In order to use the BEGIN_DISCRETE_TRANSACTION procedure, the DISCRETE_TRANSACTIONS_ENABLED initialization parameter must be set to TRUE. If this parameter is set to FALSE, all calls to BEGIN_DISCRETE_TRANSACTION are ignored and transactions requesting this service are handled as standard transactions. See the ORACLE7 Server Administrator's Guide for more information about setting initialization parameters.

Errors During Discrete Transactions

Any errors encountered during processing of a discrete transaction cause the predefined exception DISCRETE_TRANSACTION_FAILED to be raised. These errors include the failure of a discrete transaction to comply with the usage notes outlined below. (For example, calling BEGIN_DISCRETE_TRANSACTION after a transaction has begun, or attempting to modify a database block more than once during a transaction, raises the exception.)

Usage Notes

The BEGIN_DISCRETE_TRANSACTION procedure must be called before the first statement in a transaction. The call to this procedure is effective only for the duration of the transaction (that is, once the transaction is committed or rolled back, the next transaction is processed as a standard transaction).

Transactions that use this procedure cannot participate in distributed transactions.

Although discrete transactions cannot see their own changes, you can obtain the old value and lock the row, using the FOR UPDATE clause of the SELECT statement, before updating the value.

Because discrete transactions cannot see their own changes, a discrete transaction cannot perform inserts or updates on both tables involved in a referential integrity constraint.

For example, assume the EMP table has a foreign key constraint on the DEPTNO column that refers to the DEPT table. A discrete transaction cannot attempt to add a department into the DEPT table and then add an employee belonging to that department because the department is not added to the table until the transaction commits and the integrity constraint requires that the department exist before an insert into the EMP table can occur. These two operations must be performed in separate discrete transactions.

Since discrete transactions can change each database block only once, certain combinations of data manipulation statements on the same table are better suited for discrete transactions than others. One INSERT statement and one UPDATE statement used together are the least likely to affect the same block. Multiple UPDATE statements are also unlikely to affect the same block depending on the size of the affected tables. Multiple INSERT statements (or INSERT statements that use queries to specify values), however, are likely to affect the same database block. Multiple DML operations performed on separate tables do not affect the same database blocks, unless the tables are clustered.

Example

An example of a transaction type that uses the BEGIN_DISCRETE_TRANSACTION procedure is an application for checking out library books. The following procedure is called by the library application with the book number as the argument. This procedure checks to see if the book is reserved before allowing it to be checked out. If more copies of the book have been reserved than are available, the status RES is returned to the library application, which calls another procedure to reserve the book, if desired. Otherwise, the book is checked out and the inventory of books available is updated.

CREATE PROCEDURE checkout (bookno IN NUMBER (10)

                           status OUT VARCHAR(5))

AS

DECLARE

   tot_books   NUMBER(3);

   checked_out NUMBER(3);

   res        NUMBER(3);

BEGIN

   dbms_transaction.begin_discrete_transaction;

   FOR i IN 1 .. 2 LOOP

      BEGIN

         SELECT total, num_out, num_res

           INTO tot_books, checked_out, res

           FROM books

           WHERE book_num = bookno

           FOR UPDATE;

      IF res >= (tot_books - checked_out)

      THEN

         status := 'RES';

      ELSE

         UPDATE books SET num_out = checked_out + 1

            WHERE book_num = bookno;

         status := 'AVAIL'

      ENDIF;

      COMMIT;

      EXIT;

   EXCEPTION

      WHEN dbms_transaction.discrete_transaction_failed THEN

         ROLLBACK;

      END;

   END LOOP;

END;

Note the above loop construct. If the exception DISCRETE_TRANSACTION_FAILED occurs during the transaction, the transaction is rolled back, and the loop executes the transaction again. The second iteration of the loop is not a discrete transaction because the ROLLBACK statement ended the transaction; the next transaction processes as a standard transaction. This loop construct ensures that the same transaction is attempted again in the event of a discrete transaction failure.

________________________________________

Creating User Locks with ORACLE Lock Management Services

You can use ORACLE Lock Management services for your applications. It is possible to request a lock of a specific type, give it a unique name recognizable in another procedure in the same or another instance, change the lock type, and release it. Because a reserved user lock is the same as an ORACLE lock, it has all the functionality of an ORACLE lock, such as deadlock detection.

The ORACLE Lock Management services are available through procedures in the DBMS_LOCK package. The following procedures are callable from the DBMS_LOCK package:

•	ALLOCATE_UNIQUE

allocate a unique lock ID to a named lock

•	REQUEST

request a lock of a specific type

•	CONVERT

convert a lock from one type to another

•	RELEASE

release a lock

•	SLEEP

put a procedure to sleep for a specified time

User locks never conflict with ORACLE locks because they are identified with the prefix "UL." These locks can be seen via the SQL*DBA lock monitor screen and in appropriate fixed views.

User locks are automatically released when a session terminates.

Warning: This implementation efficiently supports up to a few hundred locks per session. It is strongly recommended that a standard convention be developed for using these user locks. This avoids conflicts among procedures trying to use the same locks. For example, you might want to include your company name as part of the lock name in order to ensure that your lock names do not conflict with lock names used in any supplied applications.

Security

There might be operating-system-specific limits on the maximum number of total locks available. This must be considered when using locks or making this package available to other users. Consider granting the EXECUTE privilege only to specific users or roles. A better alternative would be to create a cover package limiting the number of locks used and grant EXECUTE privilege to specific users. An example of a cover package is documented in the DBMSLOCK.SQL script file.

Procedures and Functions

This section explains the syntax and use of each of the procedures and functions contained in the DBMS_LOCK package. Note that the REQUEST, CONVERT, and RELEASE procedures are overloaded based on the first argument. You can pass either a user defined lock ID or the lock handle returned by ALLOCATE_UNIQUE to these procedures.

 ALLOCATE_UNIQUE Procedure

procedure allocate_unique(lockname in varchar2,

                 lockhandle out varchar2,

                 expiration_secs in integer default 864000);

Lock identifiers are used to allow applications to coordinate their use of locks. User-assigned lock identifiers can be a number in the range of 0 to 1073741823 or, locks can be identified by name. If you choose to identify locks by name, you can use ALLOCATE_UNIQUE to generate a unique lock identification number for these named locks.

Input parameters

lockname

Specify the name of the lock for which you want to generate a unique ID. The first session to call ALLOCATE_UNIQUE with a new lock name causes a unique lock ID to be generated and stored in the DBMS_LOCK_ALLOCATED table. The handle to this ID is then returned for this call, and all subsequent calls (usually by other sessions). Lock IDs assigned by ALLOCATE_UNIQUE are in the range of 1073741824 to 1999999999.

Do not use lock names beginning with ORA$; these names are reserved for products supplied by Oracle Corporation.

expiration_secs

Specify the number of seconds to wait after the last ALLOCATE_UNIQUE has been performed on a given lock, before allowing that lock to be deleted from the DBMS_LOCK_ALLOCATED table. The default waiting period is 10 days. Expired locks may be deleted to recover space.

Output Parameter

lockhandle

The handle to the lock ID generated by ALLOCATE_UNIQUE is returned to the caller. You can use this handle in subsequent calls to REQUEST, CONVERT, and RELEASE. LOCKHANDLE can be up to VARCHAR2(128).

A handle is returned instead of the actual lock ID to reduce the chance that a programming error can accidentally create an incorrect, but valid, lock ID. This provides better isolation between different applications that are using this package.

All sessions using a lock handle returned by calling ALLOCATE_UNIQUE using the same lock name are referring to the same lock. Different sessions can have different lock handles for the same lock, so do not pass lock handles from one session to another.

 CONVERT Function

function convert(id in integer || lockhandle in varchar2,

                 lockmode in integer,

                 timeout in number default maxwait)

   return integer;

To convert a lock from one mode to another, use the CONVERT function.

Input Parameters

id || lockhandle

Specify the user assigned lock identifier, from 0 to 1073741823, or the lock handle, returned by ALLOCATE_UNIQUE, of the lock whose mode you want to change.

lockmode

Specify the new mode that you want to assign to the given lock. The available modes and their associated integer identifiers are listed below. The abbreviations for these locks, as they appear in the V$ views and SQL*DBA monitors are shown in parenthesis.

1 - null mode

2 - row share mode (ULRS)

3 - row exclusive mode (ULRX)

4 - share mode (ULS)

5 - share row exclusive mode (ULRSX)

6 - exclusive mode (ULX)

Each of these lock modes is explained in detail in the ORACLE7 Server Concepts Manual.

timeout

Specify the number of seconds to continue trying to change the lock mode. If the lock cannot be converted within this time period, the call returns a value of 1 (timeout). Return Values The values returned by this function and their associated meanings are as follows:

0 - success

1 - timeout

2 - deadlock

3 - parameter error

4 - don't own lock specified by ID or LOCKHANDLE

5 - illegal lock handle

 REQUEST Function

function request(id in integer || lockhandle in varchar2,

                 lockmode in integer default x_mode,

                 timeout in integer default maxwait,

                 release_on_commit in boolean default FALSE,

   return integer;

To request a lock with a given mode, use the REQUEST function.

Input Parameters

id || lockhandle

The user-assigned identification number, from 0 to 1073741823, or lock handle, assigned by ALLOCATE_UNIQUE, of the lock you are requesting.

lockmode

The lock mode that you are requesting for the given lock. The available lock modes, and their associated integer representations are listed below. The abbreviations for these locks, as they appear in the V$ views and SQL*DBA monitors are shown in parenthesis.

1 - null mode

2 - row share mode (ULRS)

3 - row exclusive mode (ULRX)

4 - share mode (ULS)

5 - share row exclusive mode (ULRSX)

6 - exclusive mode (ULX)

Each of these lock modes is explained in detail in the ORACLE7 Server Concepts Manual.

timeout

Specify the time, in seconds, to continue trying to grant the lock. The default timeout is 32767 seconds. If the lock cannot be granted within this time period, the call returns a value of 1 (timeout).

release_on_commit

Set this parameter to TRUE to release the lock on commit or rollback. Otherwise, the lock is held until it is explicitly released or until the end of the session. A transaction is started if one does not already exist. Return Values The values returned by this function, and their associated meanings are as follows:

0 - success

1 - timeout

2 - deadlock

3 - parameter error

4 - already own lock specified by ID or LOCKHANDLE

5 - illegal lock handle

 RELEASE Function

function release(id in integer || lockhandle in varhchar2)

   return integer;

To explicitly release a lock previously acquired using the REQUEST function, use the RELEASE function. Locks are automatically released at the end of a session.

Input Parameter

id || lockhandle

Specify the user-assigned lock identifier, from 0 to 1073741823, or the lock handle, returned by ALLOCATE_UNIQUE, of the lock that you want to release.

Return Values

The values returned by this function, and their associated meanings are as follows:

0 - success

3 - parameter error

4 - already own lock specified by ID or LOCKHANDLE

5 - illegal lock handle

 SLEEP Procedure

procedure sleep(seconds in number);

To suspend the session for a given period of time, use the SLEEP procedure.

Input Parameter

seconds

Specify the amount of time, in seconds, to suspend the session. The smallest time increment can be entered in hundredths of a second, for example, 1.95 is a legal time value.

Example

Some uses of user locks are outlined below:

•	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

The following COBOL example shows how locks can be used to ensure that there are no conflicts when multiple people need to access a single device.

*****************************************************************

* Print Check                                                   *

* Any cashier may issue a refund to a customer returning goods. *

* Refunds under $50 are given in cash, above that by check.     *

* This code prints the check.  The one printer is opened by all *

* the cashiers to avoid the overhead of opening and closing it  *

* for every check. This means that lines of output from multiple*

* cashiers could become interleaved if we don't ensure exclusive*

* access to the printer.  The DBMSLOCK package is used to ensure*

* exclusive access.                                             *

*****************************************************************

CHECK-PRINT

*

*    Get the lock "handle" for the printer lock.

*

   MOVE "CHECKPRINT" TO LOCKNAME-ARR.

   MOVE 10 TO LOCKNAME-LEN.

   EXEC SQL EXECUTE

      BEGIN ALLOCATE_UNIQUE ( :LOCKNAME, :LOCKHANDLE );

      END; END-EXEC.

*

*   Lock the printer in exclusive mode (default mode).

*

   EXEC SQL EXECUTE

      BEGIN REQUEST ( :LOCKHANDLE );

      END; END-EXEC.

*

*   We now have exclusive use of the printer, print the check.

*

 ...

*

*   Unlock the printer so other people can use it

*

   EXEC SQL EXECUTE

      BEGIN RELEASE ( :LOCKHANDLE );

      END; END-EXEC.

________________________________________

Signalling Events in the Database with Alerters

This package provides support for the asynchronous (as opposed to polling) notification of database events. By appropriate use of this package and database triggers, an application can cause itself to be notified whenever values of interest in the database are changed.

For example, suppose a graphics tool is displaying a graph of some data from a database table. The graphics tool can, after reading and graphing the data, wait on a database alert (DBMS_ALERT.WAITONE) covering the data just read. The tool automatically wakes up when the data is changed by any other user. All that is required is that a trigger be placed on the database table which then performs a signal (DBMS_ALERT.SIGNAL) whenever the trigger is fired.

Alerts are transaction based. This means that the waiting session does not get alerted until the transaction signalling the alert commits.

There can be any number of concurrent signallers of a given alert, and there can be any number of concurrent waiters on a given alert.

A waiting application is blocked in the database and cannot do any other work.

Security

Security on this package can be controlled by granting EXECUTE on this package to selected users or roles. You might want to write a cover package on top of this one that restricts the alert names used. EXECUTE privilege on this cover package can then be granted rather than on this package.

Procedures and Functions

This section explains the syntax and use of each of the procedures and functions associated with the DBMS_ALERT package.

 REGISTER Procedure

procedure register(name in varchar2);

This procedure allows a session to register interest in an alert of name NAME. A session can register interest in an unlimited number of alerts. Alerts should be deregistered when the session no longer has any interest (see "REMOVE Procedure").

Warning: Alert names beginning with 'ORA$' are reserved for use for products provided by Oracle Corporation.

 REMOVE Procedure

procedure remove(name in varchar2);

This procedure allows a session that is no longer interested in an alert named NAME to remove that alert from its registration list. Removing an alert reduces the amount of work done by signalers of the alert.

If a session dies without removing the alert, that alert is eventually (but not immediately) cleaned up.

 SET_DEFAULTS Procedure

procedure set_defaults(polling_interval in number);

In case a polling loop is required (see page A - 18), the POLLING_INTERVAL is the time, in seconds, to sleep between polls. The default interval is five seconds.

 SIGNAL Procedure

procedure signal(name in varchar2,

                 message in varchar2);

Signal an alert.

Input parameters

name

Specify the name of the alert to signal. The effect of the SIGNAL call only occurs when the transaction in which it is made commits. If the transaction rolls back, the SIGNAL call has no effect. All sessions that have registered interest in this alert are notified. If the interested sessions are currently waiting, they are awakened. If the interested sessions are not currently waiting, then they are notified the next time they do a wait call. Multiple sessions can concurrently perform signals on the same alert. However, the first session blocks concurrent sessions until the first session commits.

message

Message, of 1800 bytes or less, to associate with this alert. This is passed to the waiting session. The waiting session might be able to avoid reading the database after the alert occurs by using the information in this message.

 WAITANY Procedure

procedure waitany(name out varchar2,

                  message out varchar2,

                  status out integer,

                  timeout in number default maxwait);

Wait for an alert to occur for any of the alerts for which this session is registered. The same session that waits for the alert may also first signal the alert. In this case remember to commit after the signal and prior to the wait; otherwise a lock request exception (status 4) occurs.

Input parameters

timeout

Specify the maximum time to wait for an alert. If no alert occurs before TIMEOUT seconds, this call returns with a status of 1 (timeout).

Output parameters

name

The name of the alert that occurred.

message

The message associated with the alert. This is the message provided by the SIGNAL call. Note that if multiple signals on this alert occurred before the WAITANY call, then the message corresponds to the most recent signal call. Messages from prior signal calls are discarded.

status

The values returned and their associated meanings are as follows.

0 - alert occurred

1 - timeout occurred

 WAITONE Procedure

procedure waitone(name in varchar2, message out varchar2,

                  status out integer,

                  timeout in number default maxwait);

Wait for the specified alert to occur. A session that is the first to signal an alert can also wait for the alert, in a subsequent transaction. Failure to commit after the signal and before the wait results in a lock request exception (status 4).

Input parameters

name

Specify the name of the alert to wait for.

timeout

Specify the maximum time to wait for this alert. If no alert occurs before TIMEOUT seconds, then this call returns with a status of 1 (timeout).

Output parameters

message

The message associated with the alert. This is the message provided by the SIGNAL call. Note that if multiple signals on this alert occurred before the WAITONE call, then the message corresponds to the most recent signal call. Messages from prior signal calls are discarded.

status

The values returned and their associated meanings are as follows:

0 - alert occurred

1 - timeout occurred

Variations

The application can register for multiple events and can then wait for any of them to occur using the WAITANY call.

An application can also supply an optional TIMEOUT parameter to the WAITONE or WAITANY calls. A TIMEOUT of 0 returns immediately if there is no pending alert.

The signalling session can optionally pass a message that will be received by the waiting session.

Alerts can be signalled more often than the corresponding application WAIT calls. In such cases the older alerts are discarded. The application always gets the latest alert (based on transaction commit times).

If the application does not require transaction based alerts, then the DBMS_PIPE package may provide a useful alternative; see page A - 19.

If the transaction is rolled back after the call to DBMS_ALERT.SIGNAL, no alert occurs.

It is possible to receive an alert, read the data, and find that no data has changed. This is because the data changed after the prior alert, but before the data was read for that prior alert.

Example

Suppose you want to graph average salaries by department, for all employees. Your application needs to know whenever EMP is changed. Your application would look similar to the code below.

dbms_alert.register('emp_table_alert');

    readagain:

   /* ... read the emp table and graph it */

      status := dbms_alert.waitone('emp_table_alert', :message);

      if status = 0 then goto readagain; else

      /* ... error condition */

The EMP table would have a trigger similar to the following example:

CREATE TRIGGER emptrig AFTER INSERT OR UPDATE OR DELETE ON emp

    BEGIN

      dbms_alert.signal('emp_table_alert', 'message_text');

   END;

When the application is no longer interested in the alert, it makes the following request:

dbms_alert.remove('emp_table_alert');

This reduces the amount of work required by the alert signaller. If a session exits (or dies) while there exist registered alerts, they are eventually cleaned up by future users of this package.

The above example guarantees that the application always sees the latest data, although it may not see every intermediate value.

Checking for Alerts

In most cases, ORACLE is event-driven; that is, there are no polling loops.  There are two cases where polling loops can occur:

•	Shared mode.  If your database is running in shared mode, a polling loop is required to check for alerts from another instance. The polling loop defaults to one second and is setable by the SET_DEFAULTS call.

•	WAITANY call.  If you use the WAITANY call, and a signalling session does a signal but does not commit within one second of the signal, then a polling loop is required so that this uncommitted alert does not camouflage other alerts. The polling loop begins at a one second interval and exponentially backs off to 30-second intervals.

________________________________________

Sending Messages Between Sessions with Pipes

The DBMSPIPE.SQL package allows sessions in the same instance to communicate with each other. ORACLE pipes are similar to the pipes used with UNIX or DOS.

Working within one instance, pipes are independent of transactions. Each pipe works asynchronously, allowing multiple readers and writers of the same pipe.

A pipe is automatically started when referenced for the first time, and it disappears when it no longer contains data. Because the pipe is stored in the shared global area, there is some space usage overhead until the data is aged out of the cache.

In general, a message is built using one or more calls to the PACK_MESSAGE procedure, which adds items to the local message buffer. The information in this buffer is sent using the SEND_MESSAGE procedure, which designates the pipe used to send the message. On the receiving end, there must be a similar call to the RECEIVE_MESSAGE procedure, which receives the message on the named pipe. The UNPACK_MESSAGE procedure is then used to access each of the items in the message.

Security

Security on this package can be controlled by granting EXECUTE on this package to selected users or roles. You might prefer to write cover packages that only expose particular features or pipes to selected users or roles.

Procedures and Functions

This section explains the syntax and use of each of the procedures and functions associated with the DBMS_PIPES package.

 NEXT_ITEM_TYPE Function

function next_item_type return integer

This function returns the type of the next item in the local message buffer. The integer that is returned corresponds to the following types:

0 - no more items

6 - NUMBER

9 - VARCHAR2

12 - DATE

 PACK_MESSAGE Procedure

procedure pack_message(item in varchar2 | number | date)

This procedure packs an item into the local message buffer. Specify an ITEM of type VARCHAR2, NUMBER or DATE to add to the buffer.

In addition to the data bytes, each item in the buffer requires one byte for the type and two bytes for the length of the item. One additional byte is needed to terminate the message. If the message buffer exceeds 4096 bytes, the ORA-2000 exception is raised.

 PURGE Procedure

procedure purge(pipename in varchar2)

Empty the contents of PIPENAME. The local buffer might be overwritten with messages as they are purged from the pipe. You can use this procedure to free the memory associated with a pipe. An empty pipe is aged out of the shared global area according to the least recently used algorithm.

 RECEIVE_MESSAGE Function

function receive_message(pipename in varchar2,

                         timeout in integer)

   return integer

Call this procedure to receive a message on the named pipe and copy it into the local message buffer. Use the UNPACK_MESSAGE procedure to access the individual items in the message.

Input Parameters

pipename

Specify the name of the pipe on which you want to receive a message. Names beginning with ORA$ are reserved for use by Oracle.

timeout

Warning: Specify the timeout period in seconds. This is the time to wait to receive a message. The default value is the constant, MAXWAIT, which is defined as 86400000 (1000 days). A timeout of 0 allows you to read without blocking.

Return Values

The integer values returned have the following meaning.

0 - success

1 - timed out

2 - record in pipe too large for buffer (this should not happen.)

3 - interrupted

 RESET_BUFFER Procedure

procedure reset_buffer

This procedure resets the PACK_MESSAGE and UNPACK_MESSAGE positioning indicators to 0. This procedure is not generally needed.

 SEND_MESSAGE Function

function send_message(pipename in varchar2,

                      timeout in integer,

                      maxpipesize in integer)

   return integer

This function sends a message on the named pipe. The message is contained in the local message buffer that was filled with calls to the PACK_MESSAGE procedure.

Input Parameters

pipename

Specify the name of the pipe on which you want to place the message.

Warning: Do not use a pipe name beginning with ORA$; these names are reserved for use by Oracle Corporation.

timeout

Specify the timeout period in seconds. This is the time to wait while attempting to place a message on the pipe; the return values are explained below. The default value is the constant MAXWAIT, which is defined as 86400000 (1000 days).

maxpipesize

Specify the maximum size allowed for the pipe, in bytes. The total size of all of the messages on the pipe cannot exceed this amount. The message is blocked if it exceeds this maximum. The default MAXPIPESIZE is 8192 bytes.

The MAXPIPESIZE for a pipe becomes a part of the characteristics of the pipe and persists for the life of the pipe. Callers of SEND_MESSAGE with larger values cause the MAXPIPESIZE to be increased. Callers with a smaller value simply use the existing, larger value. Specifying MAXPIPESIZE as part of the SEND_MESSAGE procedure eliminates the need for a separate call to open the pipe.

Return Values

The integer values returned by this procedure have the following meanings:

0 - success

1 - timed out

3 - interrupted

This procedure can time out either because it cannot get a lock on the pipe or because the pipe remains too full to be used.

 UNIQUE_SESSION_NAME Function

function unique_session_name return varchar2

This procedure returns a name that is unique among all of the sessions that are currently connected to a database. Multiple calls to this routine from the same session always return the same value. The return value can be up to 30 bytes.

 UNPACK_MESSAGE Procedure

procedure unpack_message(item out varchar2 | number | date)

This procedure unpacks an item from the local message buffer. The ITEM can be of type VARCHAR2, NUMBER, or DATE. If the message buffer contains no more items, or if the item received is not of the same type as that requested, the ORA-2000 exception is raised.

Example

The following example shows a procedure that could be called by a PL/SQL program to place debugging information in a pipe:

CREATE OR REPLACE PROCEDURE debug(info VARCHAR2) IS

   s NUMBER;

BEGIN

   DBMS_PIPE.PACK_MESSAGE(info);

   s := DBMS_PIPE.SEND_MESSAGE('plsql_debug');

   IF s <> 0 THEN

       RAISE_APPLICATION_ERROR(-2000, 'Debug error');

   ENDIF;

END;

/

The following code is a Pro*C example of a pipe used to retrieve the messages sent using the DEBUG procedure and display them in a window. Any errors raised by the PL/SQL code by calling DEBUG are noticed by the Pro*C pipe application and displayed in a second window.

#include <stdio.h>

#include <string.h>

exec sql begin declare section;

   VARCHAR username[64];

   int     status;

   char    retval[128];

exec sql end declare section;

exec sql include sqlca;

void sql_error(void);

main(argc, argv)

int argc;

char **argv;

{

   /* prepare username */

   if (argc  1)

      strncpy(username.arr, argv[1], sizeof (username.arr) - 1);

   else

      strcpy(username.arr, "SCOTT/TIGER");

   username.len = strlen(username.arr);

   exec sql whenever sqlerror do sql_error();

   exec sql connect :username;

   printf("connected\n");

/* start an endless loop to look for and print

   messages on the pipe */

   for (;;)

   {

      exec sql execute

         declare

            s integer;

            chr varchar2(200);

         begin

            chr := '';

            s := dbms_pipe.receive_message('plsql_debug');

            if s = 0 then

               dbms_pipe.unpack_message(chr);

            end if;

            :status := s;

            :retval := chr;

         end;

      end-exec;

      if (status == 0)

         printf("\n%s\n", retval);

      else

         printf("abnormal status, value is %d\n", status);

   }

}

void sql_error(void)

{

   char msg[1024];

   int rlen, len;

   len = sizeof(msg);

   sqlglm(msg, &len, &rlen);

   printf("ORACLE ERROR\n");

   printf("%.*s\n", rlen, msg);

   exit(1);

}

________________________________________

Output From Stored Procedures and Triggers

You can output messages from a trigger, procedure, or package using the DBMS_OUTPUT package. The PUT and PUT_LINE procedures in this package allow you to place information in a buffer that can be displayed when the trigger, procedure, or package is executed. This information can be displayed by calling the GET_LINE procedure, or by using the special SET SERVEROUTPUT ON command in SQL*Plus or SQL*DBA; otherwise, these messages are ignored. This package is especially useful for displaying debugging information.

For example, if you wanted to debug a trigger, you could include one or more lines in your code similar to the following line:

dbms_output.put_line('The value now is:'||:new.col);

You could then use SQL*DBA or SQL*PLUS, with the server output option enabled, to fire the trigger and display the debugging messages that you included.

Procedures and Functions

This section explains the syntax and use of each of the procedures and functions contained in the DBMS_OUTPUT package. Note that the PUT and PUT_LINE procedures are overloaded based on the type of item that is passed in to the procedure. You can pass either a NUMBER, DATE, or VARCHAR2 to these procedures. All items are converted to VARCHAR2 as they are retrieved.

If you pass an item of type NUMBER or DATE, when that item is retrieved, it is formatted with TO_CHAR using the default format. If you want to use a different format, you should pass in the item as VARCHAR2 and format it explicitly.

 DISABLE Procedure

procedure disable;

This procedure disables calls to PUT, PUT_LINE, NEW_LINE, GET_LINE, and GET_LINES, and purges the buffer of any remaining information. As with ENABLE, you do not need to call this procedure if you are using the server output option of SQL*DBA or SQL*Plus.

 ENABLE Procedure

procedure enable (buffer_size in integer default 2000);

This procedure enables calls to PUT, PUT_LINE, NEW_LINE, GET_LINE, and GET_LINES. Calls to these procedures are ignored if the DBMS_OUTPUT package is not enabled.

You must specify the amount of information, in bytes, to buffer. Items are stored in the DBMS_OUTPUT package. If the buffer size is exceeded, you receive the following error message.

 -20000, ORU-10027: buffer overflow, limit of buffer_limit bytes.

Multiple calls to ENABLE are allowed. It is not necessary to call this procedure to use the server output option of SQL*DBA or SQL*Plus. If there are multiple calls to enable, BUFFER_SIZE is the largest of the values specified. The maximum size is 1000000 and the minimum is 2000.

 GET_LINE Procedure

procedure get_line(line out varchar2, status out integer);

This procedure retrieves a single line of buffered information, excluding a final newline character. The maximum length of LINE is 255 bytes.

Any lines not retrieved before the next call to PUT, PUT_LINE, or NEW_LINE are discarded in order to avoid confusing them with the next message.

If the call completes successfully, the status returns as 0. If there are no more lines in the buffer, the status is 1.

 GET_LINES Procedure

procedure get_lines(lines out chararr, numlines in out integer);

This procedure retrieves an array of lines and can be used instead of GET_LINE to reduce the number of calls to the server. Use NUMLINES to specify the number of lines that you want to retrieve from the buffer. After retrieving the specified number of lines, the procedure returns the number of lines actually retrieved. If this number is less than the number of lines requested, there are no more lines in the buffer.

Any lines remaining in the buffer are purged by the next call to PUT, PUT_LINE, or NEW_LINE.

Each line in the LINES array can be up to 255 bytes long.

 NEW_LINE Procedure

procedure new_line;

This procedure places an end-of-line marker in the buffer. You commonly use this procedure after one or more calls to PUT to indicate the end of a message. Every call to NEW_LINE generates a line that is returned by a call to GET_LINE.

 PUT Procedure

procedure put(item varchar2 | number | date);

Specify the piece of information that you want to place in the buffer. Use this procedure if you want to add multiple pieces of information to the buffer before calling NEW_LINE to end the line. GET_LINE and GET_LINES do not return a line that has not been terminated with a newline character. If you exceed the buffer limit, you receive an error message.

 PUT_LINE Procedure

procedure put_line(item varchar2 | number | date);

Specify the piece of information that you want to place in the buffer. This item is automatically followed by an end-of-line marker. Every call to PUT_LINE generates a line that is returned by a call to GET_LINE. If you exceed the buffer limit, you receive an error message.

Example

The DBMS_OUTPUT package is commonly used to debug stored procedures and triggers. For a debugging example, see page 7 - 14. This package can also be used to allow a user to retrieve information about an object and format this output, as shown in the following example.

This example assumes that the user has used the EXPLAIN PLAN command to retrieve information about the execution plan for a statement and store it in PLAN_TABLE, and that the user has assigned a statement ID to this statement. The example EXPLAIN_OUT procedure retrieves the information from this table and formats the output in a nested manner that more closely depicts the order of steps undergone in processing the SQL statement.

 /****************************************************************/

/* Create EXPLAIN_OUT procedure. User must pass STATEMENT_ID to */

/* to procedure, to uniquely identify statement.                */

/****************************************************************/

CREATE OR REPLACE PROCEDURE explain_out

   (statement_id IN VARCHAR2) AS

   /* Retrieve information from PLAN_TABLE into cursor */

   /* EXPLAIN_ROWS.                                    */

   CURSOR explain_rows IS

      SELECT level, id, position, operation, options,

         object_name

      FROM plan_table

      WHERE statement_id = explain_out.statement_id

      CONNECT BY PRIOR id = parent_id

         AND statement_id = explain_out.statement_id

      START WITH id = 0

       ORDER BY id;

BEGIN

   /* Loop through information retrieved from PLAN_TABLE */

   FOR line IN explain_rows LOOP

      /* At start of output, include heading with        */

      /* estimated cost.                                 */

      IF line.id = 0 THEN

         DBMS_OUTPUT.PUT_LINE ('Plan for statement '

            || statement_id

            || ', estimated cost = ' || line.position);

      END IF;

      /* Output formatted information. LEVEL is used to */

      /* determine indention level.                     */

      DBMS_OUTPUT.PUT_LINE (lpad(' ',2*(line.level-1)) ||

         line.operation || ' ' || line.options || ' ' ||

         line.object_name);

   END LOOP;

END;

________________________________________

Describing Stored Procedures

You can use the DESCRIBE_PROCEDURE procedure in the DBMS_DESCRIBE package to describe the arguments of a stored procedure. The primary client of this package is the ORACLE Call Interface Describe Procedure (ODESSP). The ODESSP OCI call can be used to call DESCRIBE_PROCEDURE from a user program. The client specifies a procedure, and DESCRIBE_PROCEDURE returns a set of indexed tables with the results. For more information on ODESSP, see your Programmer's Guide to the ORACLE Call Interfaces. Other stored procedures can use this package by using the VARCHAR2_TABLE and NUMBER_TABLE types.

Security

This package is available to PUBLIC and performs its own security checking based on the object being described.

DESCRIBE_ PROCEDURE

Use the DESCRIBE_PROCEDURE procedure to create a set of indexed tables that contain information about the arguments to a given stored procedure or package.

Procedures and Functions

This section explains the syntax and use of the procedure associated with the DBMS_DESCRIBE package.

 DESCRIBE_PROCEDURE Procedure

procedure describe_procedure(object_name in varchar2,

                             database_name in varchar2,

                             overload out number_table,

                             position out number_table,

                             argument_name out

                             varchar2_table,

                             level out number_table,

                             datatype out number_table,

                             default_value out number_table,

                             attributes out number_table,

                             in_out out number_table,

                             length out number_table,

                             precision out _number_table

                             scale out number_table,

                             radix out number_table

This procedure describes the arguments for a given stored procedure or packaged procedure. The arguments are ordered by position.

Input Parameters

procedure_name

The name of the procedure being described. The format is:

[[part1.]part2.]part3[@dblink]

The syntax for this parameter follows the rules used for identifiers in SQL. The name be a synonym. This parameter is required and may not be null. The total length of the name cannot exceed 197 bytes.

An incorrectly specified OBJECT_NAME can result in one of the following exceptions:

ORA-20000 - A package was specified. You can only specify a stored procedure, stored function, packaged procedure or packaged function.

ORA-20001 - The procedure or function that you specified does not exist within the given package.

ORA-20002 - The object that you specified is a remote object. This procedure cannot currently describe remote objects.

ORA-20003 - The object that you specified is invalid and cannot be described.

ORA-20004 - The object was specified with a syntax error.

reserved1, reserved2

These parameters are reserved for future use. Currently, they must be set to null or to an empty string.

Output Parameters

overload

A unique number assigned to the procedure signature. If a procedure is overloaded, this field holds a different value for each version of the procedure.

position

Position of the argument in the parameter list.

level

If the argument is a composite type, such as record, this parameter returns the level of the datatype. See page A-32 for an example of its use.

argument_name

The name of the argument associated with the procedure that you are describing.

datatype

The ORACLE datatype of the argument being described. The available datatype are:

0 - placeholder for procedures with no arguments

1 - VARCHAR2

2 - NUMBER

3 - NATIVE INTEGER (for PL/SQL's BINARY_INTEGER)

8 - LONG

12 - DATE

23 - RAW

24 - LONG RAW

96 - CHAR (ANSI FIXED CHAR)

106 -  MLS LABEL

250 - PL/SQL RECORD

251 - PL/SQL TABLE

252 - PL/SQL BOOLEAN

default_value

This parameter is 1 if the argument being described has a default value; otherwise, the value is 0.

in_out

This value of this parameter indicates if the argument being described is an:

0 - IN parameter

1 - OUT parameter

2 - IN/OUT parameter

length

The value of this parameter is the data length, in bytes, of the argument being described.

precision

If the argument being described is of datatype NUMBER, this parameter is the precision of that number.

scale

If the argument being described is of datatype NUMBER, this parameter is the scale of that number.

radix

If the argument being described is of datatype NUMBER, this parameter is the radix of that number.

spare

This parameter is reserved for future enhancements.

Example

One use of the DESCRIBE_PROCEDURE procedure would be as an external service interface.

For example, consider a client that provides an OBJECT _NAME of SCOTT.ACCOUNT_UPDATE where ACCOUNT_UPDATE is an overloaded function with specification:

type number_table is table of number index by binary_integer;

table account (account_no number, person_id number,

               balance number(7,2))

table person  (person_id number(4), person_nm varchar2(10))

function ACCOUNT_UPDATE (account number,

                         person person%rowtype,

                         amounts number_table,

                         trans_date date)

                         return accounts.balance%type;

function ACCOUNT_UPDATE (account number,

                         person person%rowtype,

                         amounts number_table,

                         trans_no number)

                         return accounts.balance%type;

The describe of this procedure might look similar to the output shown below.

overload position  argument level  datatype length prec scale rad

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

0        0                0  NUMBER     22    0     0    0

0        1   ACCOUNT      0  NUMBER     22    0     0    0

0        2   PERSON       0  RECORD      0    0     0    0

0        2     PERSON_ID  1  NUMBER     22    0     0    0

0        2     PERSON_NM  1  VARCHAR2   10    0     0    0

0        3   AMOUNTS      0  ARRAY       0    0     0    0

0        3                1  NUMBER     22    0     0    0

0        4   TRANS_NO     0  NUMBER     22    0     0    0

1        0                0  NUMBER     22    0     0    0

1        1   ACCOUNT      0  NUMBER     22    0     0    0

1        2   PERSON       0  RECORD      0    0     0    0

1        2    PERSON_ID   1  NUMBER     22    0     0    0

1        2    PERSON_NM   1  VARCHAR2   10    0     0    0

1        3   AMOUNTS      0  ARRAY       0    0     0    0

1        3                1  NUMBER     22    0     0    0

1        4   TRANS_DATE   0  NUMBER     22    0     0    0


APPENDIX B. PERFORMANCE DIAGNOSTIC TOOLS

The primary tool for monitoring the performance of ORACLE is the collection of dynamic performance tables. These tables have names beginning with "V$" and are documented in parts of this Guide that describe how they can be used for monitoring performance. All dynamic performance tables are listed in Appendix B "Data Dictionary Reference" of the ORACLE7 Server Administrator's Guide.

This appendix describes additional performance diagnostic tools. These tools and the dynamic performance tables can help you monitor and tune applications that run against ORACLE.

The performance tools described in this appendix are:

•	the SQL trace facility

•	the EXPLAIN PLAN command

The output of the EXPLAIN PLAN command reflects the behavior of the ORACLE optimizer. Because the optimizer is likely to evolve between versions of ORACLE, output from the EXPLAIN PLAN command will also evolve. Similarly, the SQL trace facility and TKPROF program are also subject to change in future versions of ORACLE. Such changes will be documented in future versions of ORACLE manuals.

________________________________________

The SQL Trace Facility

The SQL trace facility provides performance information on individual SQL statements. The SQL trace facility generates the following statistics for each statement:

•	parse, execute, and fetch counts

•	CPU and elapsed times

•	physical reads and logical reads

•	number of rows processed

•	misses on the library cache

You can enable the SQL trace facility for a session or for an instance. When the SQL trace facility is enabled, performance statistics for all SQL statements executed in a user session or in an instance are placed into a trace file.

You can run the TKPROF program to format the contents of the trace file and place the output into a readable output file. As options, TKPROF can also:

•	determine the execution plans of SQL statements

•	create a SQL script that stores the statistics in the database

Because running the SQL trace facility increases system overhead, you should enable it only when tuning your SQL statements, and disable it when you are finished.

Using the SQL Trace Facility

Follow these steps to use the SQL trace facility:

1.	Set initialization parameters to prepare ORACLE for using the SQL trace facility.

2.	Enable the SQL trace facility and run your application. This step produces a trace file containing statistics for the SQL statements issued by the application.

3.	Run TKPROF to translate the trace file created in Step 2 into a readable output file. This step can also optionally create a SQL script that stores the statistics in the database.

4.	Interpret the output file created in Step 3.

5.	Optionally, run the SQL script produced in Step 3 to store the statistics in the database.

Each of these steps is discussed in the following sections.

Setting Initialization Parameters for the SQL Trace Facility

Before running your application with the SQL trace facility enabled, be sure these initialization parameter are set appropriately:

TIMED_STATISTICS	This parameter enables and disables the collection of timed statistics, such as CPU and elapsed times, by the SQL trace facility as well as the collection of certain statistics in the dynamic performance tables. The default value of FALSE disables timing. A value of TRUE enables timing. Enabling timing causes extra timing calls for low-level operations.

MAX_DUMP_FILE_SIZE	This parameter specifies the maximum size of trace files in operating system blocks. The default is 500. If you find that your trace output is truncated, increase the value of this parameter before generating another trace file.

USER_DUMP_DEST	This parameter specifies the destination for the trace file. The destination must be fully specified according to the conventions of your operating system. The default value for this parameter is the default destination for system dumps on your operating system.

Enabling the SQL Trace Facility

You can enable the SQL trace facility for either:

•	an individual session

•	the ORACLE instance

 Enabling Tracing for a Session

To enable the SQL trace facility for your session, issue this SQL statement:

ALTER SESSION

    SET SQL_TRACE = TRUE

To disable the SQL trace facility for your session, issue this SQL statement:

ALTER SESSION

    SET SQL_TRACE = FALSE

You may need to modify your application to contain the ALTER SESSION command. For example, to issue the ALTER SESSION command in SQL*Forms Version 3, invoke SQL*Forms using the -s option, or invoke SQL*Forms (Design) using the statistics option. For more information on SQL*Forms, see the SQL*Forms Designer's Reference manual.

The SQL trace facility is also automatically disabled for your session when your application disconnects from ORACLE.

 Enabling the SQL Trace Facility for an Instance

To enable the SQL trace facility for your ORACLE instance, set the value of the initialization parameter SQL_TRACE to TRUE. This value causes statistics to be collected for all sessions.

Once the SQL trace facility has been enabled for the instance, it may be disabled for an individual session with this SQL statement:

ALTER SESSION

SET SQL_TRACE = FALSE

 Generating Trace Files

When the SQL trace facility is enabled for a session, ORACLE generates a trace file containing statistics for traced SQL statements for that session. When the SQL trace facility is enabled for an instance, ORACLE creates a separate trace file for each session.

Because ORACLE writes these trace files to the user dump destination, be sure you know how to distinguish them by name.

If your operating system retains multiple versions of files, be sure your version limit is high enough to accommodate the number of trace files you expect the SQL trace facility to generate.

The generated trace files may be owned by an operating system user other than yourself. This user must make the trace files available to you before you can use TKPROF to format them.

Once the SQL trace facility has generated a number of trace files, you can either:

•	Run TKPROF on each individual trace file producing a number of formatted output files, one for each session

•	Append the trace files together and then run TKPROF on the result to produce a formatted output file for the entire instance.

Note: Trace files generated immediately after instance startup contain data that reflects the activity of the startup process. In particular, they reflect a disproportionate amount of I/O activity as caches in the System Global Area (SGA) are filled. For the purposes of tuning, ignore such trace files.

Running TKPROF

TKPROF accepts as input a trace file produced by the SQL trace facility and produces a formatted output file. TKPROF can also be used to generate execution plans. Invoke TKPROF using this syntax:

If you invoke TKPROF with no arguments, online help is displayed.

Use the following arguments with TKPROF:

filename1	specifies the input file, a trace file containing statistics produced by the SQL trace facility. This file can be either a trace file produced for a single session or a file produced by appending together individual trace files from multiple sessions.

filename2	specifies the file to which TKPROF writes its formatted output.

EXPLAIN	determines the execution plan for each SQL statement in the trace file and writes these execution plans to the output file. TKPROF determines execution plans by issuing the EXPLAIN PLAN command after connecting to ORACLE with the user and password specified in this parameter. The specified user must have CREATE SESSION system privileges.

TABLE	specifies the schema and name of the table into which TKPROF temporarily places execution plans before writing them to the output file. If the specified table already exists, TKPROF deletes its rows, uses it for the EXPLAIN PLAN command, and then deletes its rows. If this table does not exist, TKPROF creates it, uses it, and then drops it.

The specified user must be able to issue INSERT, SELECT, and DELETE statements against the table. If the table does not already exist, the user must

also be able to issue CREATE TABLE and DROP TABLE statements.

For these privileges to issue these statement, see the ORACLE7 Server SQL Language Reference Manual.

This option allows multiple individuals to concurrently run TKPROF with the same user in the EXPLAIN value. These individuals can specify different TABLE values and avoid destructively interfering with each other's processing on the temporary plan table.

If you use the EXPLAIN parameter without the TABLE parameter, TKPROF uses the table PROF$PLAN_TABLE in the schema of the user specified by the EXPLAIN parameter. If you use the TABLE parameter without the EXPLAIN parameter, TKPROF ignores the TABLE parameter.

INSERT	creates a SQL script that stores the trace file statistics in the database. TKPROF creates this script with the name filename3. This script creates a table and inserts a row of statistics for each traced SQL statement into the table.

SYS	enables and disables the listing of SQL statements issued by the user SYS, or recursive SQL statements into the output file. The default value of YES causes TKPROF to list these statements. The value of NO causes TKPROF to omit them.

Note that this parameter does not affect the optional SQL script. The SQL script always inserts statistics for all traced SQL statements, including recursive SQL statements.

SORT	sorts the traced SQL statements in descending order of the specified sort option before listing them into the output file. If more than one option is specified, the output is sorted in descending order by the sum of the values specified in the sort options. If you omit this parameter, TKPROF lists statements into the output file in ascending order of when each was first issued.

The sort options are:

PRSCNT	number of times parsed

PRSCPU	CPU time spent parsing

PRSELA	elapsed time spent parsing

PRSDSK	number of physical reads from disk during parse

PRSQRY	number of consistent mode block reads during parse

PRSCU	number of current mode block reads during parse

PRSMIS	number of library cache misses during parse

EXECNT	number of executes

EXECPU	CPU time spent executing

EXEELA	elapsed time spent executing

EXEDSK	number of physical reads from disk during execute

EXEQRY	number of consistent mode block reads during execute

EXECU	number of current mode block reads during execute

EXEROW	number of rows processed during execute

EXEMIS	number of library cache misses during execute

FCHCNT	number of fetches

FCHCPU	CPU time spent fetching

FCHELA	elapsed time spent fetching

FCHDSK	number of physical reads from disk during fetch

FCHQRY	number of consistent mode block reads during fetch

FCHCU	number of current mode block reads during fetch

FCHROW	number of rows fetched

PRINT	lists only the first integer sorted SQL statements into the output file. If you omit this parameter, TKPROF lists all traced SQL statements. Note that this parameter does not affect the optional SQL script. The SQL script always inserts statistics for all traced SQL statements.

Example	This example runs TKPROF, accepts a trace file named KERVMS_RPK2_FG_SQLDBA_007.TRC and writes a formatted output file named OUTPUTA.PRF:

TKPROF KERVMS_RPK2_FG_SQLDBA_007.TRC OUTPUTA.PRF

EXPLAIN=SCOTT/TIGER TABLE=SCOTT.TEMP_PLAN_TABLE_A INSERT=STOREA.SQL SYS=NO SORT=(EXECPU,FCHCPU) PRINT=10

This example is likely to be longer than a single line on your terminal screen and you may have to use continuation characters, depending on your operating system.

Note the other parameters in this example:

•	The EXPLAIN value causes TKPROF to connect as the user SCOTT and use the EXPLAIN PLAN command to generate the execution plan for each traced SQL statement.

•	The TABLE value causes TKPROF to use the table TEMP_PLAN_TABLE_A in the schema SCOTT as a temporary plan table.

•	The INSERT value causes TKPROF to generate a SQL script named STOREA.SQL that stores statistics for all traced SQL statements in the database.

•	The SYS parameter with the value of NO causes TKPROF to omit recursive SQL statements from the output file.

•	The SORT value causes TKPROF to sort the SQL statements in order of the sum of the CPU time spent executing and the CPU time spent fetching rows before writing them to the output file.

•	The PRINT value of 10 causes TKPROF to write statistics for the first 10 sorted SQL statements to the output file.

Interpretting TKPROF Output

The following listing shows TKPROF output for one SQL statement as it appears in the output file:

SELECT * FROM emp, dept WHERE emp.deptno = dept.deptno

call   count      cpu    elapsed     disk    query current    rows

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

Parse      1     0.16      0.29         3       13       0       0

Execute    1     0.00      0.00         0        0       0       0

Fetch      1     0.03      0.26         2        2       4      14

Misses in library cache during parse: 1

Parsing user id: 8

Rows     Execution Plan

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

     14  MERGE JOIN

      4    SORT JOIN

      4      TABLE ACCESS (FULL) OF 'DEPT'

     14    SORT JOIN

     14      TABLE ACCESS (FULL) OF 'EMP'

For this statement, TKPROF output has these parts:

•	the text of the SQL statement

•	the SQL trace statistics in tabular form

•	the number of library cache misses for the parsing and execution of the statement

•	the user initially parsing the statement

•	the execution plan generated by EXPLAIN PLAN

 SQL Trace Facility Statistics

TKPROF lists the statistics for a SQL statement returned by the SQL trace facility in rows and columns. Each row corresponds to one of three steps of SQL statement processing:

Parse	This step translates the SQL statement into an execution plan. This step includes checks for proper security authorization and checks for the existence of tables, columns, and other referenced objects.

Execute	This step is the actual execution of the statement by ORACLE. For INSERT, UPDATE, and DELETE statements, this step modifies the data. For SELECT statements, the step identifies the selected rows.

Fetch	This step retrieves rows returned by a query. Fetches are only performed for SELECT statements.

The step for which each row contains statistics is identified by the value of the call column.

The other columns of the SQL trace facility output are combined statistics for all parses, all executes, and all fetches of a statement:

count	number of times a statement was parsed, executed, or fetched.

cpu	total CPU time in seconds for all parse, execute, or fetch calls for the statement.

elapsed	total elapsed time in seconds for all parse, execute, or fetch calls for the statement.

disk	total number of data blocks physically read from the data files on disk for all parse, execute, or fetch calls.

query	total number of buffers retrieved in consistent mode for all parse, execute, or fetch calls. Buffers are usually retrieved in consistent mode for queries.

current	total number of buffers retrieved in current mode. Buffers are often retrieved in current mode for INSERT, UPDATE, and DELETE statements.

The sum of query and current is the total number of buffers accessed.

rows	total number of rows processed by the SQL statement. This total does not include rows processed by subqueries of the SQL statement.

For SELECT statements, the number of rows returned appears for the fetch step.

For UPDATE, DELETE, and INSERT statements, the number of rows processed appears for the execute step.

Resolution of Statistics     Since timing statistics have a resolution of one hundredth of a second, any operation on a cursor that takes a hundredth of a second or less may not be timed accurately. Keep this in mind when interpreting statistics. In particular, be careful when interpreting the results from simple queries that execute very quickly.

Recursive Calls     Sometimes in order to execute a SQL statement issued by a user, ORACLE must issue additional statements. Such statements are called recursive calls or recursive SQL statements. For example, if you insert a row into a table that does not have enough space to hold that row, ORACLE makes recursive calls to allocate the space dynamically. Recursive calls are also generated when data dictionary information is not available in the data dictionary cache and must be retrieved from disk.

If recursive calls occur while the SQL trace facility is enabled, TKPROF produces statistics for the recursive SQL statements and clearly marks them as recursive SQL statements in the output file. Note that the statistics for a recursive SQL statement are included in the listing for that statement, not in the listing for the SQL statement that caused the recursive call. So when you are calculating the total resources required to process a SQL statement, you should consider the statistics for that statement as well as those for recursive calls caused by that statement. Note that setting the TKPROF command line parameter to NO suppresses the listing of recursive calls in the output file.

 Library Cache Misses

TKPROF also lists the number of library cache misses resulting from parse and execute steps for each SQL statement. These statistics appear on separate lines following the tabular statistics. If the statement resulted in no library cache misses, TKPROF does not list the statistic. In the example, the statement resulted in one library cache miss for the parse step and no misses for the execute step.

 User Issuing the SQL Statement

TKPROF also lists the user ID of the user issuing each SQL statement. If the TKPROF input file contained statistics from multiple users and the statement was issued by more than one user, TKPROF lists the ID of the last user to parse the statement. The user ID of all database users appears in the data dictionary in the column ALL_USERS.USER_ID.

 Execution Plan

If you specify the EXPLAIN parameter on the TKPROF command line, TKPROF uses the EXPLAIN PLAN command to generate the execution plan of each SQL statement traced. For more information on interpreting execution plans, see the section "Example of EXPLAIN PLAN Output" on page B - 20. TKPROF also displays the number of rows processed by each step of the execution plan.

Storing SQL Trace Facility Statistics

You may want to keep a history of the statistics generated by the SQL trace facility for your application and compare them over time. TKPROF can generate a SQL script that creates a table and inserts rows of statistics into it. This script contains:

•	a CREATE TABLE statement that creates an output table named TKPROF_TABLE

•	INSERT statements that add rows of statistics, one for each traced SQL statement, to the TKPROF_TABLE

After running TKPROF, you can run this script to store the statistics in the database.

 Generating the TKPROF Output SQL Script

When you run TKPROF, use the INSERT parameter to specify the name of the generated SQL script. If you omit this parameter, TKPROF does not generate a script.

 Editing the TKPROF Output SQL Script

After TKPROF has created the SQL script, you may want to edit the script before running it:

•	If you have already created an output table for previously collected statistics and you want to add new statistics to the existing table, remove the CREATE TABLE statement from the script. The script will then insert the new rows into the existing table.

•	If you have created multiple output tables, perhaps to store statistics from different databases in different tables, edit the CREATE TABLE and INSERT statements to change the name of the output table.

 Querying the Output Table

The following CREATE TABLE statement creates the TKPROF_TABLE:

CREATE TABLE tkprof_table

    (date_of_insert    DATE,

    cursor_num        NUMBER,

    depth             NUMBER,

    user_id           NUMBER,

    parse_cnt         NUMBER,

    parse_cpu         NUMBER,

    parse_elap        NUMBER,

    parse_disk        NUMBER,

    parse_query       NUMBER,

    parse_current     NUMBER,

    parse_miss        NUMBER,

    exe_count         NUMBER,

    exe_cpu           NUMBER,

    exe_elap          NUMBER,

    exe_disk          NUMBER,

    exe_query         NUMBER,

    exe_current       NUMBER,

    exe_miss          NUMBER,

    exe_rows          NUMBER,

    fetch_count       NUMBER,

    fetch_cpu         NUMBER,

    fetch_elap        NUMBER,

    fetch_disk        NUMBER,

    fetch_query       NUMBER,

    fetch_current     NUMBER,

    fetch_rows        NUMBER,

    sql_statement     LONG)

These columns help you identify a row of statistics by these columns:

SQL_STATEMENT	The column value is the SQL statement for which the SQL trace facility collected the row of statistics. Note that because this column has datatype LONG, you cannot use it in expressions or WHERE clause conditions.

DATE_OF_INSERT	The column value is the date and time when the row was inserted into the table. Note that this value is not exactly the same as the time the statistics were collected by the SQL trace facility. Most output table columns correspond directly to the statistics that appear in the formatted output file. For example the PARSE_CNT column value corresponds to the count statistic for the parse step in the output file. These output table columns serve special purposes:

DEPTH	This column value indicates the level of recursion at which the SQL statement was issued. For example, a value of 1 indicates that a user issued the statement. A value of 2 indicates ORACLE generated the statement as a recursive call to process a statement with a value of 1 (a statement issued by a user). A value of n indicates ORACLE generated the statement as a recursive call to process a statement with a value of n-1.

USER_ID	This column value identifies the user issuing the statement. This value also appears in the formatted output file.

CURSOR_NUM	This column value is used by ORACLE to keep track of the cursor to which each SQL statement was assigned. Note that the output table does not store the statement's execution plan.

Example	This query returns the statistics from the output table. These statistics correspond to the formatted output shown in the section "Interpretting TKPROF Output" on page B - 8.

    SELECT * FROM tkprof_table;

    DATE_OF_INSERT CURSOR_NUM DEPTH USER_ID PARSE_CNT PARSE_CPU PARSE_ELAP

    -------------- ---------- ----- ------- --------- --------- ---------- 	    27-OCT-1993             1     0       8         1        16         29

    PARSE_DISK PARSE_QUERY PARSE_CURRENT PARSE_MISS EXE_COUNT EXE_CPU

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

             3          13             0          1         1       0

    EXE_ELAP EXE_DISK EXE_QUERY EXE_CURRENT EXE_MISS EXE_ROWS FETCH_COUNT

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

           0        0         0           0        0        0           1

    FETCH_CPU FETCH_ELAP FETCH_DISK FETCH_QUERY FETCH_CURRENT FETCH_ROWS

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

            3         26          2           2             4         14

    SQL_STATEMENT

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

 	    SELECT * FROM EMP, DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO

________________________________________

The EXPLAIN PLAN Command

The EXPLAIN PLAN command displays the execution plan chosen by the ORACLE optimizer for SELECT, UPDATE, INSERT, and DELETE statements. A statement's execution plan is the sequence of operations that ORACLE performs to execute the statement. By examining the execution plan, you can see exactly how ORACLE executes your SQL statement. This information can help you determine whether the SQL statement you have written takes advantage of the indexes available. For the syntax of the EXPLAIN PLAN command, see the ORACLE7 Server SQL Language Reference Manual.

Creating the Output Table

Before you can issue an EXPLAIN PLAN statement, there must exist a table to hold its output. You can create an output table through either of these means:

•	You can run the SQL script UTLXPLAN.SQL to create a sample output table called PLAN_TABLE in your schema. The exact name and location of this script may vary depending on your operating system. PLAN_TABLE is the default table into which the EXPLAIN PLAN statement inserts rows describing execution plans.

•	You can issue a CREATE TABLE statement to create an output table with any name you choose. In this case, you can issue an EXPLAIN PLAN statement and direct its output to this table.

Any table used to store the output of the EXPLAIN PLAN command must have the same column names and datatypes as this PLAN_TABLE:

CREATE TABLE plan_table

    (statement_id     VARCHAR2(30),

    timestamp        DATE,

    remarks          VARCHAR2(80),

    operation        VARCHAR2(30),

    options          VARCHAR2(30),

    object_node      VARCHAR2(30),

    object_owner     VARCHAR2(30),

    object_name      VARCHAR2(30),

    object_instance  NUMERIC,

    object_type      VARCHAR2(30),

    search_columns   NUMERIC,

    id               NUMERIC,

    parent_id        NUMERIC,

    position         NUMERIC,

    other            LONG)

Output Table Columns

The PLAN_TABLE used by the EXPLAIN PLAN command contains the following columns:

STATEMENT_ID	The value of the option STATEMENT_ID parameter specified in the EXPLAIN PLAN statement.

TIMESTAMP	The date and time when the EXPLAIN PLAN statement was issued.

REMARKS	Any comment (of up to 80 bytes) you wish to associate with each step of the explained plan. If you need to add or change a remark on any row of the PLAN_TABLE, use the UPDATE statement to modify the rows of the PLAN_TABLE.

OPERATION	The name of the internal operation performed in this step. Table B - 1 beginning on page B - 20 shows values for this column.

In the first row generated for a statement, the column contains one of these values, depending on the type of the statement:

'DELETE STATEMENT'

'INSERT STATEMENT'

'SELECT STATEMENT'

'UPDATE STATEMENT'

OPTIONS	A variation on the operation described in the OPERATION column. Table B - 1 beginning on page B - 20 shows values for this column.

OBJECT_NODE	The name of the database link used to reference the object (a table name or view name).

OBJECT_OWNER	The name of the user that owns the schema containing the table or index.

OBJECT_NAME	The name of the table or index.

OBJECT_INSTANCE	A number corresponding to the ordinal position of the object as it appears in the original statement. The numbering proceeds from left to right, outer to inner with respect to the original statement text. Note that view expansion will result in unpredictable numbers.

OBJECT_TYPE	A modifier that provides descriptive information about the object, for example, NON-UNIQUE for indexes.

SEARCH_COLUMNS	Not currently used.

ID	A number assigned to each step in the execution plan.

PARENT_ID	The ID of the next execution step that operates on the output of the ID step. For a description of how ID and PARENT_ID show the order of processing of the execution plan, see the section "Example of EXPLAIN PLAN Output" on page B - 20.

POSITION	The order of processing for steps that all have the same PARENT_ID.

In the first row generated for a SQL statement, this column contains the cost of the statement as estimated by the optimizer's cost-based approach. For statements that use the rule-based approach, this column is null for the first generated row.

OTHER	Other information that is specific to the execution step that a user may find useful. For example, for distributed queries, OTHER might contain the text of the SQL statement sent to a remote database.

Table B - 1 lists each combination of OPERATION and OPTION values produced by the EXPLAIN PLAN command and its meaning within an execution plan.

OPERATION	OPTION	Description

AGGREGATE	GROUP BY	A retrieval of a single row that

is the result of applying a group

function to a group of selected

rows.

AND-EQUAL	An operation that accepts

multiple sets of ROWIDS and

returns the intersection of the

sets, eliminating duplicates.

This operation is used for the

single-column indexes access

path.

CONNECT BY	A retrieval of rows in a

hierarchical order for a query

containing a CONNECT BY

clause.

CONCATENATION	An operation that accepts

multiple sets of rows and

returns the union-all of the

sets.

COUNTING	An operation that counts the

number of rows selected from a

table.

FILTER	An operation that accepts a set

of rows, eliminates some of

them, and returns the rest.

FIRST ROW	A retrieval on only the first row

selected by a query.

FOR UPDATE	AN operation that retrieves and

locks the rows selected by a

query containing a FOR

UPDATE clause.

INDEX*	UNIQUE SCAN	A retrieval of a single ROWID

from an index.

INDEX*	RANGE SCAN	A retrieval of one or more

ROWIDs from an index.

Indexed values are scanned in

ascending order.

INDEX*	RANGE SCAN 	A retrieval of one or more

DESCENDING	ROWIDs from an index.

Indexed values are scanned in

descending order.

INTERSECTION	An operation that accepts two

sets of rows and returns the

intersection of the sets,

eliminating duplicates.

MERGE JOIN+	An operation that accepts two

sets of rows, each sorted by a

specific value, combines each

row from one set with the

matching rows from the other,

and returns the result.

MERGE JOIN+	OUTER	A merge join operation to

perform an outer join

statement.

CONNECT BY	A retrieval of rows in a

hierarchical order for a query

containing a CONNECT BY

clause.

MINUS	An operation thart accepts two

sets of rows and returns rows

that appear in the first set but

not in the second, elimnating

duplicates.

NESTED LOOPS+	An operation that accepts two

sets of rows, an outer set and

an inner set.  ORACLE

compares each row of the outer

set with each row of the inner

set and returns those rows that

satisfy a condition.

NESTED LOOPS+	OUTER	A nested loops operation to

perform an outer join

statement.

PROJECTION	An internal operation

REMOTE	A retrieval of data from a

remote database

SEQUENCE	AN operation involving acces

sing values of a sequence

SORT	UNIQUE	An operation that sorts a set of

rows to eliminate duplicartes.

GROUP BY	An operation that sorts a set of

rows into groups for a query

with a GROUP BY clause.

JOIN	An operation that sorts a set of

rows prior to a merge-join op

eration.

ODER BY	An operation that sorts a set of

rows for a query with an OR

DER BY clause.

TABLE ACCESS*	FULL	A reetrieval of all rows from a

table.

CLUSTER	A retrieval of rows from a table

based on a value of the key of

an indexed cluster..

HASH	A retrieval of rows from a table

based on a value of the key of

hash cluster.

BY ROWID	A retrieval of a row from a

table based on its ROWID.

UNION	An operation that accepts two

sets of rows and returns the

union of the sets, elimnating

duplicates.

VIEW	An operation that performs a

view's query and then returns

the resulting rows to another

operation.

Table B - 1.  OPERATION and OPTION Values Produced by the EXPLAIN PLAN Command.

*  These operations are access methods.

+  These operations are join operations.

Both access methods and join operations are discussed in Chapter 13 "The Optimizer" of the ORACLE7 Server Concepts Manual.

Example of EXPLAINPLAN Output

The following example shows a SQL statement and its corresponding execution plan generated by using the EXPLAIN PLAN command.

This query retrieves names and related information for employees whose salary is not within any range of the SALGRADE table:

SELECT ename, job, sal, dname

   FROM emp, dept

   WHERE emp.deptno = dept.deptno

      AND NOT EXISTS

         (SELECT *

            FROM salgrade

            WHERE emp.sal BETWEEN losal AND hisal)

This EXPLAIN PLAN statement generates an execution plan and places the output in PLAN_TABLE:

EXPLAIN PLAN

   SET STATEMENT_ID = 'Emp_Sal'

   FOR SELECT ename, job, sal, dname

      FROM emp, dept

      WHERE emp.deptno = dept.deptno

         AND NOT EXISTS

            (SELECT *

               FROM salgrade

               WHERE emp.sal BETWEEN losal AND hisal)

 Table Format ofEXPLAIN PLAN Output

This SELECT statement generates the following output:

SELECT operation, options, object_name, id, parent_id, position

    FROM plan_table

    WHERE statement_id = 'Emp_Sal'

    ORDER BY id

OPERATION         OPTIONS   OBJECT_NAME   ID  PARENT_ID   POSITION

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

SELECT STATEMENT                           0                     5

FILTER                                     1         0           0

NESTED LOOPS                               2         1           1

TABLE ACCESS      FULL      EMP            3         2           1

TABLE ACCESS      FULL      DEPT           4         2           2

TABLE ACCESS      FULL      SALGRADE       5         1           3

The ORDER BY clause returns the steps of the execution plan sequentially by ID value. However, ORACLE does not perform the steps in this order. Since PARENT_ID receives information from ID, observe that more than one ID step fed PARENT_ID. For example, step 2, a merge join, and step 7, a table access, both fed step 1. A nested, visual representation of the processing sequence is shown in the next section.

The value of the POSITION column for the first row of output indicates that the optimizer estimates the cost of executing the statement with this execution plan to be 2.

 Nested Format of EXPLAIN PLAN Output

This type of SELECT statement generates a nested representation of the output that more closely depicts the order of steps undergone in processing the SQL statement. The order resembles a "tree-structure" illustrated in Figure B - 1.

SELECT LPAD(' ',2*(LEVEL-1))||operation||' '||options

   ||' '||object_name

   ||' '||DECODE(id, 0, 'Cost = '||position) "Query Plan"

   FROM plan_table

   START WITH id = 0 AND statement_id = 'Emp_Sal'

   CONNECT BY PRIOR id = parent_id AND statement_id ='Emp_Sal'

Query Plan

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

SELECT STATEMENT   Cost = 5

   FILTER

      NESTED LOOPS

         TABLE ACCESS FULL EMP

         TABLE ACCESS FULL DEPT

      TABLE ACCESS FULL SALGRADE

The tree structure illustrates how operations that occur during the execution of a SQL statement feed one another. Each step in the execution plan is assigned a number (representing the ID column of the PLAN_TABLE) and is depicted by a "node." The result of each node's operation passes to its parent node, which uses it as input.


APPENDIX C. SQL*FORMS AND ORACLE

This appendix describes how you can write your SQL*Forms applications to take advantage of ORACLE features. These features include:

•	stored procedures

•	roles

•	integrity constraints

•	database triggers

•	shared SQL areas

•	cost based optimizer

Note: This appendix applies to Version 3 and Version 4 of SQL*Forms, used with ORACLE7.

________________________________________

Stored Procedures

The procedural option lets you create stored database procedures. Database procedures are similar to SQL*Forms procedures, except that they execute within ORACLE, not within the client (SQL*Forms). One important difference is that server-side PL/SQL procedures do not understand references to SQL*Forms bind variables (such as :BLOCK.FIELDNAME, :GLOBAL.VARNAME, or :SYSTEM.CURSOR_FIELD) or SQL*Forms built-in routines (such as next_field or previous_block).

Any data that procedures need for processing must be passed via parameters of the appropriate datatype, via package variables, or by selecting from tables. For this reason, if you are creating any SQL*Forms procedures that you might want to later convert to stored procedures, you should structure them such that they accept inputs and return results in parameters. This allows you to migrate the procedure into the database simply by adding the word CREATE in front of the PROCEDURE declaration, and running the resulting script in SQL*Plus.

 Syntax

SQL*Forms provides support for calling database procedures and packages directly from SQL*Forms triggers and form-level procedures. The syntax for the call is identical to any form-level procedure you might normally include in your form.

DECLARE   ------------/ Example SQL*Forms Trigger /---------

   ld DATE;

   ln NUMBER;

   lv VARCHAR2(30);

BEGIN

   /* Calling form-level procedure/function */

   forms_procedure_name( ld, ln, lv );

   ld := forms_function_name ( ln, lv );

   /* Calling database procedure/function */

   database_procedure_name ( ld, ln, lv );

   ld := database_function_name( ln, lv );

END;

Supported Datatypes

Stored procedures, functions, and packages are created using Version2 of PL/SQL within the ORACLE database. Because SQL*Forms is built on PL/SQL Version 1 (for backward compatibility reasons only), the following PL/SQL Version 2 datatypes are supported for parameters and as function return values:

•	VARCHAR2 (with a limit of 2000 bytes)

•	NUMBER

•	DATE

•	BOOLEAN

Your stored procedures and functions can internally be written using all of the new PL/SQL Version 2 datatypes and functionality. The above restrictions on datatypes only apply to the interface that your stored routines have with their Version 1 PL/SQL counterparts, namely, parameters and return values.

An attempt to reference a stored procedure or stored function that uses unsupported parameter or return-value datatypes results in the failure to recognize the stored subprograms, which results in one of the following error messages:

PL/SQL error 313 at line xxx, column yyy

'PROCNAME' not declared in this scope

or

PL/SQL error 201 at line xxx, column yyy

identifier 'FUNCTNAME' must be declared

Supported Constructs

When invoking a stored procedure or function, only the following subset of possible usages is supported:

         ProcName(arg1, ..., argN)

         FuncName(arg1, ..., argN)

PackName.ProcName(arg1, ..., argN)

PackName.FuncName(arg1, ..., argN)

To access a subprogram (that is, a procedure or function) in another user's schema or one at a remote database, you must create a synonym to hide the username or database link name from the PL/SQL compiler, such that the results take the form:

         ProcSynonym(arg1, ..., argN)

          FuncSynonym(arg1, ..., argN)

PackName.ProcSynonym(arg1, ..., argN)

PackName.FuncSynonym(arg1, ..., argN)

For example, to call the package function LIBOWNER.LIB_HR.GET_SSN, you would create a synonym for the LIB_HR package that includes the schema name as follows:

CREATE SYNONYM lib_hr_syn

           FOR libowner.lib_hr;

Then invoke the function from within your form as:

ss_num := lib_hr_syn.get_ssn(:Emp.Empno);

If the package function was at a remote site, accessible via a database link named BASEL, for example, you could then create a synonym for the package, including the database link name:

CREATE SYNONYM basel_lib_hr_syn

          FOR libowner.lib_hr@basel;

Then invoke the function from within your PL/SQL code as:

ss_num := basel_lib_hr_syn.get_ssn(:Emp.Empno);

Alternatively, you can create a synonym for the function itself, hiding both the schema and database link information:

CREATE SYNONYM basel_lib_hr_get_ssn_syn

           FOR libowner.lib_hr.get_ssn@basel;

Then invoke the function from SQL*Forms as:

ss_num := basel_lib_hr_get_ssn_syn(:Emp.Empno);

Of course, any of the synonyms in the previous examples could have been created as PUBLIC synonyms as appropriate.

Name Resolution

When encountering the name of an identifier that could be a procedure or function, the PL/SQL compiler uses a precedence mechanism to resolve possible ambiguities.

If an identifier such as PROCNAME is encountered, which has the structure of a procedure or function, the compiler uses the first match found in the following search order.

1.	Is it defined within the current PL/SQL block?

2.	Is it a standard PL/SQL command?

3.	Is it a SQL*Forms packaged procedure or function?

4.	Is it a user-defined SQL*Forms-level procedure or function?

5.	Is it defined in package DBMS_STANDARD on the server-side?

6.	Does the current user have access to any such procedure or function on the server-side?

If none of the above are true, then the compiler signals one of the following errors.

PL/SQL error 313 at line xxx, column yyy

'PROCNAME' not declared in this scope

or

PL/SQL error 201 at line xxx, column yyy

identifier 'FUNCTNAME' must be declared

When you generate a form containing references to stored procedures, functions, or packages, SQL*Forms must first ensure that the stored subprogram that you reference exits on the server during compilation. SQL*Forms must also include any intermediate access routine for each stored subprogram that you reference.

There is one access routine for each procedure, function, or package that is referenced. If you reference functions or procedures within a package, they will use the access routine associated with the entire package. The access routines handle the integration between PL/SQL Version 1 and Version 2, and are included in the .FRM file of your generated form. These access routines are not visible to the designer.

Considerations

Use a database procedure instead of a SQL*Forms procedure when:

•	It provides a standard functionality that other tools would want to share, such as validation or calculations.

•	It performs a significant amount of DML operations. This allows them to be performed in a bundle by the database and may reduce network traffic in a client/server environment.

•	The procedure does not need to call SQL*Forms built-in routines, or reference SQL*Forms variables.

•	New PL/SQL Version 2 functionality, such as TABLES, RECORDS, or TYPES, is required, since SQL*Forms continues to use PL/SQL Version 1.

Restrictions

SQL*Forms disables commits in stored procedures and functions that are called while SQL*Forms (Runform) is active. A stored procedure or function cannot issue a COMMIT or ROLLBACK when called by SQL*Forms. An attempt to do so raises the error:

ORA-00034: Commit and Rollback from PL/SQL disabled for this session

However, if your C program calls SQL*Forms through the IAPCAL() interface, your stored procedures that are called by the C program via the IAPCAL routine can issue commits once the user has exited the form.

Because SQL*Forms creates the access routine for each stored subprogram that your trigger or SQL*Forms-level-procedure PL/SQL code references, it is not possible to write a form containing calls to stored procedures or functions that will generate against both ORACLE Version 6 and ORACLE7. Once a form includes a reference to at least one stored subprogram, then it must be generated against an ORACLE7 database. Otherwise, compilation errors result when the names of stored subprograms cannot be resolved by the PL/SQL compiler.

Character (CHAR or VARCHAR2) values passed into a stored procedure or function, passed out from a stored procedure, or returned from a stored function cannot exceed 2000 characters. Actual character parameters exceeding 2000 characters are truncated to a length of 2000. The truncation that occurs on IN, OUT, or return character values is performed without raising the PL/SQL VALUE_ERROR exception, and without raising a SQL*Forms truncation error.

Packaged Procedures

Procedures and functions can be organized into groups, or packages. SQL*Forms only provides direct support for invoking stored procedures and functions, and not for directly referencing package variables or package cursors. Therefore, you must design a function or procedure to manipulate package variables and package cursors within the code on the server side. If their datatypes are among the four supported types listed earlier in this section, values of package variables and fetched cursor data can be returned to the SQL*Forms caller via parameters or a function return value.

Supplied Packages

The following packages are supplied with ORACLE7:

DBMS_STANDARD

DBMS_TRANSACTION

DBMS_SESSION

DBMS_DDL

DBMS_UTILITY

From SQL*Forms, you can invoke procedures included in any of these packages by using the syntax package.procedure. For example:

DBMS_SESSION.SET_ROLE('role');

These packages are described in Appendix A. If you use any of these packages, you should be aware that:

•	Unlike the default security behavior, all of the procedures in these special packages are run as the invoking user, not as the procedure or package owner.

•	When they are installed, all of these packages have public synonyms of the same name created for them, and have GRANT EXECUTE to PUBLIC.

________________________________________

Roles

Support for the SET ROLE command in SQL*Forms Version 3 is provided via the DBMS_SESSION.SET_ROLE procedure. Your application can enable a particular role at startup in order to ensure that all application users have the proper access. The SET_ROLE procedure also allows you to specify a role that is identified by a password, for additional security. Because this password would be known only to the application, individual users could not enable the role.

By assigning a password to the role, you can restrict access to the role to SQL*Forms users only. For example, a PRE-FORM trigger could attempt to enable the role necessary to run the current form, and trap the ORA-01919 error, "Role_name does not exist", if the user had not been granted the necessary role.

If you do not want to modify existing applications, you can still simplify privilege maintenance by ensuring that the necessary roles are qualified as DEFAULT roles for your users, so the related privileges are enabled automatically when they log on. If you prefer, you can continue to use privileges exactly as before, by granting each privilege directly to each user. Users of SQL*Forms who do not have the correct privilege on a particular object continue to receive the message "ORACLE Error -- Unable to Perform...", because access to that object is not permitted in their security domain.

Examples

The following two examples show how to implement the checking and setting of roles from your SQL*Forms applications.

/* ROLE_IS_SET: Checks if a role is set for current user

 *

 * Returns:  TRUE   if role passed as parameter is set for

 *                  current user

 *           FALSE  otherwise

 */

FUNCTION role_is_set( fp_rname VARCHAR2 )

RETURN BOOLEAN

IS

   lv_tmp    VARCHAR2(1);

   lv_fndrec BOOLEAN;

   CURSOR roles_enabled

      IS SELECT 'x'

         FROM session_roles

         WHERE role = UPPER( fp_rname );

BEGIN

   OPEN roles_enabled;

   FETCH roles_enabled INTO lv_tmp;

   lv_fndrec := (roles_enabled%FOUND);

   CLOSE roles_enabled;

   RETURN( lv_fndrec);

END;

/* SET_THE_ROLE: Attempts to set the role passed as a

 *               parameter

 *

 * If the role requires a password, then pass the string

 * 'ROLENAME IDENTIFIED BY PASSWORD' rather than simply

 * passing 'ROLENAME' as the argument.

 *

 * Returns: TRUE   if successful as setting the role

 *          FALSE  otherwise.

 */

FUNCTION set_the_role( fp_rname VARCHAR2 )

RETURN BOOLEAN

IS

   /* ORA-1979: Missing or invalid password... */

   wrong_password exception;

   pragma exception_init( wrong_password, -1979 );

   /* ORA-1919: Role does not exist */

   role_does_not exist exception;

   pragma exception_init(role_does_not_exist, -1919 );

BEGIN

   /* Call the stored procedure to perform the SET ROLE */

   dbms_session.set_role( fp_rname );

   RETURN( TRUE );

EXCEPTION

   /* Handle the two probable errors */

   WHEN role_does_not_exist

      OR wrong_password   THEN

      RETURN( FALSE );

END;

Using these procedures, you could implement a simple PRE-FORM trigger such as:

IF NOT( role_is_set('payroll') OR set_the_role('payroll'))

   THEN

      MESSAGE("You are not authorized to run Payroll.');

      PAUSE;

      RAISE FORM_TRIGGER_FAILURE;

   END IF;

END IF;

SQL*Menu Roles versus ORACLE Roles

There is no overlap between the definitions of SQL*Menu roles and ORACLE roles. In SQL*Menu, roles are simply named lists of ORACLE users. Using these groups of account names, menu item privileges can be assigned without regard to eventual changes to the group's members. SQL*Menu has not been modified to drive its runtime application security scheme from ORACLE roles.

A SQL*Menu PL/SQL command item could, however, SELECT from the view USER_ROLE_PRIVS to determine what ORACLE roles have been granted to the current user, and base an applications decision on the outcome of this SELECT statement. In this way, a menu could use information stored in the database regarding ORACLE roles.

There are additional views that can give other ORACLE role information dynamically at runtime to the SQL*Forms and SQL*Menu application designer: ROLE_ROLE_PRIVS, ROLE_SYS_PRIVS, and ROLE_TAB_PRIVS.

________________________________________

Integrity Constraints

Data verification can occur within ORACLE, as well as at the application level. By checking the data at the application level, you can ensure that the users of a particular application receive immediate, useful, and appropriate help and error messages when they access a table. Checking at the database level ensures that no incorrect data can be entered in the table, regardless of which application or tool is used.

You should be aware that all of the enabled constraints for a table are checked for each record that is INSERTED, UPDATED, and DELETED. In particular, newly enabled constraints can return new errors to your application as invalid data is encountered. You might want to add extra error handling to your existing applications to handle constraint violations that might arise. Error handling is discussed on page C - 14.

 DEFAULT Values

Note that if a column is declared with a DEFAULT value, ORACLE only assigns the DEFAULT value when the record is inserted, provided that the given column is not listed among the columns in the INSERT clause. Since SQL*Forms always lists all of the columns (that is, database fields) in a block for INSERTs and UPDATEs, the DEFAULT is never automatically assigned unless you either remove the field in question from the SQL*Forms block or mark it as a non-database field. You should ensure that all database fields have the appropriate default value specified as part of the SQL*Forms definition of the field. You might also consider one of the following alternatives:

•	Code an ON-INSERT trigger to override the normal SQL*Forms insert processing.

•	Use a PRE-FORM trigger to retrieve the DEFAULT values from the database and store these values in a SQL*Forms global variable. You could then create an ON-NEW-RECORD trigger that would use these global variables to populate the appropriate fields in the database.

•	Retrieve the default values from the database, and use a PRE-INSERT trigger to assign these values to database fields, as appropriate. This trigger should only assign values to database fields that were not assigned values before the user pressed COMMIT.

You should also be aware that some forms-based operations may become unnecessary when constraints are enabled. Deletion of detail records when a corresponding master is removed, for example, is handled by ORACLE if ON DELETE CASCADE is specified for the parent-child foreign key relationship. You might prefer to use this database feature instead of the automatically generated SQL*Forms PRE-DELETE triggers.

Master/Detail Blocks and Referential Integrity

Applications that include master/detail blocks coordinated via the automatically generated triggers and procedures in SQL*Forms should require no modification when running against tables with declarative referential integrity constraints enabled. SQL*Forms' default logic prevents the deletion of a master record when outstanding detail records exist, unless the design specified the "[X] Delete Details" option when creating the child block. In the latter case, SQL*Forms uses a PRE-DELETE trigger to first delete the detail records, then the master is deleted.

However, if you move the standard PRE-DELETE logic to the POST-DELETE trigger instead, you will encounter problems running against ORACLE when PRIMARY and FOREIGN KEY relationships have been declared and enabled on the server-side.

Waiting until the POST-DELETE trigger to delete the child records causes SQL*Forms to issue the DELETE statement for the parent record while detail records remain. This generates the following ORACLE error message:

ORA-02292: violated integrity constraint (OWNER.CONSTRAINT)

         - child record found

However, if you specified the FOREIGN KEY relationship with the ON DELETE CASCADE option, then no problem would arise, and the SQL*Forms POST_DELETE trigger would now be needlessly performing an extra DELETE statement to remove the child records that the cascade delete of the parent record would have already carried out.

________________________________________

Database Triggers

Database triggers, which are available with the procedural option, are user-defined PL/SQL routines that are automatically executed as the result of an insertion in, update to, or deletion from a table. They can be fired before or after each statement, or before or after each row that the operation affects.

Interaction Between Database Triggers and SQL*Forms Triggers

If database triggers are written to supplant SQL*Forms-side triggers, for example, to perform table auditing, then the SQL*Forms-side functionality must be disabled to avoid duplicating table operations. One possible solution is to use a package variable as a flag to communicate between the form and the server-side triggers (or procedures), so a decision can be made (inside the trigger or procedure) on whether a particular operation might have already been performed by the SQL*Forms code.

Triggers, as well as stored procedures and functions, raise errors with the RAISE_APPLICATION_ERROR procedure, assigning an error number from the special range 20000 - 20999, and providing an error message. Because it is your PL/SQL database trigger that prepares the error message, it need not be static text. These errors can be caught within the SQL*Forms application. Information on error handling is included on page C - 14.

Database triggers fire in response to a DML statement, such as INSERT, UPDATE, or DELETE, so during normal SQL*Forms commit-time processing, as SQL*Forms issues INSERT statements to add newly entered records to the database, UPDATE statements to effect changes by the operator to existing records, and DELETE statements to remove records deleted by the operator from the database, your database triggers will fire if enabled.

For example, consider the scenario where the following database triggers have been defined and enabled on the EMP table:

BEGIN DELETE

BEFORE DELETE FOR EACH ROW

AFTER DELETE

AFTER DELETE FOR EACH ROW

When the SQL*Forms operator deletes a record that has been queried, the following sequence of events occurs:

1.	Operator deletes record from screen.

2.	SQL*Forms locks the record to be deleted.

3.	Operator presses [Commit].

4.	SQL*Forms fires the PRE-COMMIT trigger.

5.	SQL*Forms fires the PRE-DELETE trigger.

6.	SQL*Forms issues a DELETE statement to delete each row.

7.	 	The database BEFORE DELETE trigger fires.

8.	The database BEFORE DELETE FOR EACH ROW trigger fires.

9.	The record is deleted.

10.	The database AFTER DELETE FOR EACH ROW trigger fires.

11.	The database AFTER DELETE trigger fires.

12.	SQL*Forms fires the POST-DELETE trigger.

13.	SQL*Forms fires the POST-COMMIT trigger.

Any error raised during the commit processing causes SQL*Forms to rollback the currently committing transaction to the savepoint it creates before initiating the commit sequence. If any database trigger fails (that is, raises an unhandled error or calls RAISE_APPLICATION_ERROR) as a result of a DML statement that SQL*Forms has issued automatically, then the "Oracle Error Occurred..." message appears. An error raised as a result of a DML statement in your PL/SQL trigger can be handled as described beginning on page C - 14. If not handled, the error produces the message "XXX-YYYYYY trigger raised unhandled exception."

Derived Fields

Database triggers can make implied changes that are not visible to SQL*Forms. This can cause SQL*Forms to issue error message ORA-04086 "trigger NEW variables collide with user specified values" if it encounters a record changed by a database trigger. Also, since SQL*Forms Version 3 always lists all of the columns (that is, database fields) in a block for INSERTs and UPDATEs, database triggers cannot compute values for derived columns in the table being updated, unless you modify your forms to use non-database fields for some derived fields.

The following example illustrates steps that you can take to avoid this problem. Suppose that you have a table, EMP, with columns WKLY_SAL and YRLY_SAL, and YRLY_SAL is derived by the trigger. To avoid this error, you could:

•	Remove the "base table" attribute of field YRLY_SAL in block BLK.

•	Create a PRE-FIELD trigger, and any other triggers that the user will invoke whenever they use records from EMP, as follows:

SELECT yrly_sal INTO :blk.yrly_sal FROM EMP;

•	Create a POST-UPDATE trigger to make sure to select the new value of YRLY_SAL each time the WKLY_SAL is updated, as follows:

SELECT yrly_sal INTO :blk.yrly_sal FROM EMP;

Alternatively, your database trigger should ensure that if a derived field is being updated, the value being assigned to the field is the same value as the trigger would assign to the derived value, and then avoid changing the column. This allows the trigger to detect that the new value is appropriate, and thus avoid trying to change it.

For example:

CREATE TRIGGER names BEFORE UPDATE OF ename, uppername ON emp

FOR EACH ROW

BEGIN

   IF NOT UPDATING ('uppername') THEN

   :new.uppername := upper(ename)

   ELSIF :new.uppername != upper (:new.ename) THEN

      raise_application_error (.....);

   ENDIF;

END;

You should review your applications to determine if database triggers can be used to provide any additional or improved functionality, or improved performance. Database triggers are especially useful for providing complex security checking and auditing. They can also be used to provide integrity checking in situations where greater complexity is required than declarative integrity constraints can provide. Just as with integrity constraints, however, you may still prefer to have your application, as well as the server, verify data integrity, in order to provide immediate and appropriate feedback to the application users.

________________________________________

Shared SQL Areas

In ORACLE, the parsed form of SQL statements is stored in the SGA, where it can be shared by all users, significantly reducing memory usage. To take advantage of this feature, the SQL statements must be identical, including spacing, capitalization, and bind variable names.

Be aware that non-quoted strings are converted to uppercase. If you use Version 2-style SQL*Forms triggers with your SQL*Forms applications, non-quoted strings are converted to lowercase. If you want to avoid these restrictions, you can have your forms call a stored procedure that contains the statements to be executed.

________________________________________

Cost Based Optimizer

The cost-based optimizer chooses an execution plan based, in part, on statistics that describe the referenced data. You do not need to modify your statements to take advantage of this new feature. You can include comments, or "hints," in your query to influence the behavior of the optimizer.

Because SQL*Forms uses PL/SQL Version 1, comments are stripped out of SQL statements. If you want to use optimizer hints, you need to have your form invoke a stored procedure that contains the statements that you want to execute.

________________________________________

Multi-threaded Server

SQL*Forms applications are well-suited to take advantage of the multi-threaded server architecture available in ORACLE7. The multi-threaded server configuration allows many user processes to share very few server processes. This can reduce system overhead and allow you to increase the number of concurrent users. See the ORACLE7 Server Concepts Manual for a full description of the multi-threaded server architecture.

________________________________________

Error Handling

There are two primary methods for trapping ORACLE errors that are returned from the kernel during the processing of your PL/SQL code:

•	create appropriate user-defined exceptions

•	evaluate the SQLCODE and SQLERRM functions in a WHEN OTHERS exception handler

Although PL/SQL includes many predefined exceptions, such as NO_DATA_FOUND, DUP_VAL_ON_INDEX, and VALUE_ERROR, the range of ORACLE errors that you need to trap cannot be completely covered. However, PL/SQL provides the facility to define your own exceptions and associate them with the occurrence of a particular ORACLE error of your choice.

The following code illustrates how to use EXCEPTION_INIT to tell PL/SQL what ORACLE error should raise your exception.

-- Example of declaring your own error-driven exceptions --

DECLARE

   -- First declare the name of the exception

   cannot_del_parent  EXCEPTION;

   -- Then associate it with the ORA-2292 error, which is

   -- "violated integrity constraint number xxx - child

   --    record found".

   --  Note error number is negative.

   PRAGMA EXCEPTION_INIT ( cannot_del_parent, -2292 );

BEGIN

   DELETE FROM PARENT_TABLE

      WHERE PRIMARY_KEY_FIELD = :BLOCK.PK;

      -- If you reach this point, everything went OK.

EXCEPTION

   -- If the error occurs, this exception is raised and

   -- can be dealt with.

WHEN cannot_del_parent THEN

   MESSAGE('You cannot remove open '||

           'order number'||:block.pk);

      RAISE FORM_TRIGGER_FAILURE;

END;

This method is best when the ORACLE error number alone is enough to allow your application to determine what has occurred. User-defined exceptions are a natural counterpart to trapping user-defined error messages.

However, some errors returned by the kernel always return a single error number, along with the name of the constraint that has been violated. An example of this follows.

ORA-02290:  violated check constraint (SCOTT.C_CK)

In this case, you need access to the error message itself in order to determine what has occurred. You must use a WHEN OTHERS clause to capture and evaluate the SQLCODE and SQLERRM. The PL/SQL functions are only available within an exception handler, and are most useful in a WHEN OTHERS clause. To get the name of the constraint that was violated (returned in uppercase), use the STRIP_CONSTRAINT_NAME function. An example using these PL/SQL functions follows:

DECLARE

   lv_sqlcode NUMBER;         -- Place to hold SQLCODE

   lv_sqlerrm VARCHAR2(240);  -- Place to hold SQLERRM

   lv_constr  VARCHAR2(41);   -- Place for constraint name

BEGIN

   UPDATE PARENT_TABLE

      SET SOME_FIELD = 5

   WHERE PRIMARY_KEY_FILED = :BLOCK.PK;

-- If you reach this point, everything went OK.

EXCEPTION

   -- If the error occurs, the exception handler gets

   -- control.

   WHEN OTHERS THEN

   lv_sqlcode := SQLCODE;

   lv_sqlerrm := SQLERRM;

   IF ( lv_sqlcode = -2290 ) THEN

      -- Strip out the name of the violated constraint

      lv_constr := strip_constraint_name( lv_sqlerrm );

      IF (lv_constr = 'SCOTT.C_CK' ) THEN

         MESSAGE( 'Code must be A, B, or C' );

         RASIE FORM_TRIGGER-FAILURE;

      END IF;

   END IF;

END;

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

-- STRIP_CONSTRAINT_NAME:  Returns constraint name from

--                         Ora error

--

-- Constraint name should appear enclosed by parentheses

-- in the Oracle errors 02290-02292 and 02296-02299.

-- Return the text between the parenthesis when passed

-- the error message text.

FUNCTION strip_constraint_name ( errmsg VARCHAR2 )

RETURN VARCHAR2

IS

   lv_pos1 NUMBER;

   lv_pos2 NUMBER;

BEGIN

   lv_pos1 := INSTR( errmsg, '(' );

   lv_pos2 := INSTR( errmsg, ')' );

   IF ( lv_pos1 = 0 OR lv_pos2 = 0 ) THEN

      RETURN ( NULL );

   ELSE

      RETURN( UPPER( SUBSTR( errmsg, lv_pos1+1,lv_pos2-lv_pos1-1)));

   END IF;

END

In order to catch ORACLE errors that are a result of database block INSERT, UPDATE, and DELETE operations, you must implement the respective ON-INSERT, ON-UPDATE, and ON-DELETE triggers to actually perform the DML operations so that you can trap the errors.

Errors related to the features discussed in this appendix that could be trapped by the first method include the following errors:

After a SET ROLE --

ORA-01919: Role ROLENAME does not exist

ORA-01979: Missing or invalid password

After relevant DML --

ORA-00001: Duplicate key in index

ORA-01400: Mandatory NOT NULL column missing

ORA-01407: cannot update mandatory (NOT NULL) column to NULL

ORA-04088: error during execution of trigger (OWNER.TRIGGERNAME)

ORA-04092: trigger may not commit or rollback

On return from database procedure/trigger/function --

ORA-06550: PL/SQL Error occurred

ORA-06501: PROGRAM_ERROR if attempting to run against V6

ORA-20000:

.

.        : User defined error message range.

.

ORA-20999:

Errors related to the features described in this appendix that would be trapped using the second method include the following errors:

After INSERT/UPDATE with bad foreign key --

ORA-02291: violated integrity constraint (OWNER.CONSTRAINT)

         - parent key not found

After DELETE without CASCADE when dependent children exit --

ORA-02292: violated integrity constraint (OWNER.CONSTRAINT)

         - child record found

After INSERT/UPDATE --

ORA-02290: violated check constraint (OWNER.CONSTRAINT)

On return from database procedure/trigger/function --

ORA-06550: PL/SQL Error occurred

ORA-06501: PROGRAM_ERROR if attempting to run against V6

ORA-20000:

.

.        : User defined error message range.

.

ORA-20999:


APPENDIX D. DATA DICTIONARY REFERENCE

This appendix contains descriptions of the data dictionary tables and views.  To see the current data dictionary on your system, query the view DICTIONARY. This appendix contains the following information:

•	SQL scripts available for altering the data dictionary or granting access to tables

•	Data dictionary views and their columns

•	Views of the dynamic performance tables - the V$ views

In Trusted ORACLE, each of the dictionary tables and views contains an additional column indicating the label of each row in the table or view. There are also additional dictionary tables and views in Trusted ORACLE, as well as additional columns in some tables and views. See the Trusted ORACLE Administrator's Guide for more information.

________________________________________

Data Dictionary SQL Script Files

Certain ORACLE SQL script files perform data dictionary functions and can be run during or after database creation. The following is a list of ORACLE SQL scripts and their functions. The standard script names are shown. On some operating systems, the names may differ. Consult your installation or user's guide for details.

Standard Scripts

These scripts are run by installations.

SQL.BSQ	Database bootstrap script.

CATALOG.SQL	Creates the standard data dictionary views.

Data Dictionary Scripts

These scripts are run by SYS to create data dictionary

CATAUDIT.SQL	Creates the auditing data dictionary views.

CATBLOCK.SQL	Creates a view callee BLOCKING_LOCKS. You can

query this view to find out which locks are clocking the

system; for example, you could find processes that have

died while holding locks, which for some reason have

not been cleaned up by PMON.

CATDBSYN.SQL	Creates private synonyms for the DBA data dictionary

views.

CATEXP.SQL	Creates roles for import and exprot and incremental

export  views.

CATLDR.SQL	Creates SQL* Loader views for direct laods.

CATNOAUD.SQL	Drops the auditing tables.

CATNOPRC.SQL	Drops the procedural object views.

CATPARR.SQL	Creates data dictionary views used for installations

with the Parallel Server option.

CATPROC.SQL	Creates data dictionary views for procedural objects and

snapshots used in installations with the procedural

option.

CATTRUST.SQL	Creates views for Trusted ORACLE.

CATSNAP.SQL	Creates views for storing and maintaining snapshots.

CATRPC.SQL	Creates data dictionary views on distributed database

information.

STANDARD.SQL	Creates PL/SQL packages for the procedural option.

DBMSSTDX.SQL	Includes extensions to the package standard.

Procedure Scripts

These scripts are also run by SYS.  They create stored procedures and packages

DBMSALRT.SQL	Creates the user-alert procedures and one supporting

view.

DBMSLOCK.SQL	Creates PL/SQL lock management packages that allow

applications to creat locks, five themn names, request

the, and release them, as well as to conver a lock from

one of seveal supported lock modes to another. Routines

are also provided to wait for a period of time beforee

re-requesting a lock. Deadlock conditions among the

locks are detected.

DBMSMAIL.SQL	Creates PL/SQL package to send mail. This routine can

be called from a trigger. See also: UTLMAIL.SQL.

DBMSOTPT.SQL	Creates output procedures for use in script debugging

and information display.

DBMSPIPE.SQL	Creates procedures for inter-process communication.

DBMSSNAP.SQL	Creates snapshot refresh procedures.

DBMSUTIL.SQL	Creates PL/SQL utility packages, including routines for

transaction management, session control,and DDL

statement execution. Also supports recompilation of all

stored PL./SQL objects.

DBMSDESC.SQL

User Scripts

These scripts are run by users

UTLBSTAT.SQL	Creates statistics tables and collects beginning statistics.

UTLCHAIN.SQL	Creates the defaulty table for storing the output of the

ANALYZE LIST CVHAINED ROWS comand.

UTLDIDXS.SQL	Displays index statistics captured by UTLIDXSS.SQL

and UTLIDXSO.SQL.

UTLDTREE.SQL	Creates the procedure and view used to show all objects

(to which a user has access) that are dependent on a

given object, including recursive dependency.

UTLESTAT.SQL	Collects ending statistics and generates a report.

UTLEXCPT.SQL	Creates the exceptions table for recording ciolations of

integrity constraints.

UTLLOCKT.SQL	Shows the lock wait-for graph in tree-Structured from

to help diagnose systems that are hung on locks.

UTLMAIL.SQL	Upgrades the mail database so that it can be accessed

via Remote Procedure Calls (RPC). See also:

DBSMAIL.SQL.

UTLMONTR.SQL	Grants access to the dynamic performance tables to

PUBLIC.

UTLOIDXS.SQL	Analyzes a column of a table, generating statistics that

can be used to evaluate its suitability for indexing.

UTLSAMPL.SQL	Creates the initial database users and tables for

experimentation and illustration.

UTLSIDXS.SQL	Analyzes index statistics for existing index columns.

Can analyze multiple tables/columns at one time.

UTLXPLAN.SQL	Creates the table used by EXPLAIN PLAN to store the

description of the statement execution plan.

Migration Scripts

For details on these scripts, see the ORACLE7 Server Migration Guide.

CATALOG6.SQL	Creates Version 6 views for compatibility.

CATEXP6.SQL	Creates the views needed for a Version 6 export.

DROPCAT6.SQL	Removes the Version 6 views and restores the data

dictionary to full ORACLE7 form.

________________________________________

Data Dictionary Views

The following is an alphabetical reference of the data dictionary views accessible to all users of an ORACLE database. Most views can be accessed by any user with the CREATE_SESSION privilege.

 The data dictionary views that begin with DBA_ are restricted.  These views can be accessed only users who have the SELECT_ANY_TABLE privilege. This privilege is assigned to the DBA role when the system is initially installed.

ALL_CATALOG	All tables, views, synonyms, and sequences accessible to the user

OWNER	Owner of the object

TABLE_NAME	Name of the object

TABLE_TYPE	Type of the object

ALL_COL_COMMENTS	Comments on columns of accessible tables and views

OWNER	Owner of the object

TABLE_NAME	Name of the object

COLUMN_NAME	Name of the column

COMMENTS	Comment on the column

ALL_COL_PRIVS	Grants on columns for which the user or PUBLIC is the grantee

GRANTOR	Name of the user who performed the grant

GRANTEE	Name of the user to whom access was

granted

TABLE_SCHEMA	Schema of the object

TABLE_NAME	Name of the object

COLUMN_NAME	Name of the column

PRIVILEGE	Privilege on the column

GRANTABLE	YES if the privileges was granted WITH

ADMIN OPTION, otherwise NO

ALL_COL_PRIVS_MADE	Grants on columns for which the user or PUBLIC is the grantee

GRANTEE	Name of the user to whom access wasgranted

OWNER	Username of the owner of the object

TABLE_NAME	Name of the object

COLUMN_NAME	Name of the column

GRANTOR	Name of the user who performed the grant

PRIVILEGE	Privilege on the column

GRANTABLE	YES if the privilege was granted WITH

ADMIN OPTION, otherwise NO

ALL_COL_PRIVS_RECD	Grants on columns for which the user or PUBLIC is the grantee

GRANTEE	Name of the user to whom access wasgranted

OWNER	Username of the owner of the object

TABLE_NAME	Name of the object

COLUMN_NAME	Name of the column

GRANTOR	Name of the user who performed the grant

PRIVILEGE	Privilege on the column

GRANTABLE	YES if the privilege was granted WITH

ADMIN OPTION, otherwise NO

ALL_CONSTRAINTS	Constraint definitions on accessible tables

OWNER	Owner of the constraint definition

CONSTRAINT_NAME	Name associated with the constraint defini

tion

CONSTRAINT_TYPE	Type of constraint definition:  C (check

constraint on a table), P(primary key),

U(unique key), R(referential integrity), or V

(with check option, on a view)

TABLE_NAME	Name associated with table with constraint

definition

SEARCH_CONDITION	Text of search condition for table check

R_OWNER	Owner of table used in referential constraint

R_CONSTRAINT_NAME	Name of unique constraint definition for ref

erenced table

DELETE_RULE	Delete rule for a referentialk constraint: CAS

CADE/NO ACTION

STATUS	 Status of constraint: ENABLED or DIS

ABLED

ALL_CONS_COLUMNS	Information about accessible columns in constraint definitions

OWNER	Owner of the constraint definition

CONSTRAINT_NAME	Name associated with the constraint defini

tion

TABLE_NAME	Name associated with table with constraint

definition

COLUMN_NAME	Name associated with column specified in the

constraint definition

POSITION	Original position of column in definition

ALL_DB_LINKS	Database links accessible to the user

OWNER	Username of the owner of the database link

DB_LINK	Name of the database link

USERNAME	Name of user when logging on

HOST	SQL*Net string for connect

CREATED	Creation time of the database link

ALL_DEF_AUDIT_OPTS	Default object-auditing options that will be applied when objects are created

ALT	Auditing ALTER WHENEVER

SUCCESSFUL / UNSUCCESSFUL

AUD	Auditing AUDIT WHENEVER

SUCCESSFUL / UNSUCCESSFUL

COM	Auditing COMMENT WHENEVER

SUCCESSFUL / UNSUCCESSFUL

DEL	Auditing DELETE WHENEVER

SUCCESSFUL / UNSUCCESSFUL

GRA	Auditing GRANT WHENEVER

SUCCESSFUL / UNSUCCESSFUL

IND	Auditing INDEX WHENEVER

SUCCESSFUL / UNSUCCESSFUL

INS	Auditing INSERT WHENEVER

SUCCESSFUL / UNSUCCESSFUL

LOC	Auditing LOCK WHENEVER

SUCCESSFUL / UNSUCCESSFUL

REN	Auditing RENAME WHENEVER

SUCCESSFUL / UNSUCCESSFUL

SEL	Auditing SELECT WHENEVER

SUCCESSFUL / UNSUCCESSFUL

UPD	Auditing UPDATE WHENEVER

SUCCESSFUL / UNSUCCESSFUL

REF	Auditing REFERENCES WHENEVER

SUCCESSFUL / UNSUCCESSFUL

EXE	Auditing EXECUTE WHENEVER

SUCCESSFUL / UNSUCCESSFUL

ALL_DEPENDENCIES	Dependencies between objects accessible to the user

OWNER	Owner of the object

NAME	Name of the object

TYPE	Type of object:  PROCEDURE, PACKAGE,

FUNCTION, PACKAGE BODY

REFERENCED_OWNER	Owner of the parent object

REFERENCED_NAME	Name of the parent object

REFERENCED_TYPE	Type of the parent object:  PROCEDURE,

PACKAGE, FUNCTION, PACKAGE BODY

REFERENCED_LINK_NAME	Name of the link to the parent object (if re

mote)

ALL_ERRORS	Grants on columns for which the user or PUBLIC is the grantee

OWNER	Owner of the object

NAME	Name of the object

TYPE	Type of object:  VIEW, PROCEDURE, PACK

AGE, FUNCTION, PACKAGE BODY<D%0>

SEQUENCE	Sequence number, for ordering

LINE	Line number at which this error occurs

POSITION	Position in the line at which this error occurs

TEXT	Text of the error

ALL_INDEXES	Grants on columns for which the user or PUBLIC is the grantee

OWNER	Username of the owner of the index

STATUS	State of the ides:

DIRECT LOAD or VALID

INDEX_NAME	Name of the index

TABLE_OWNER	Owner of the indexed object

TABLE_NAME	Name of the indexed object

TABLE_TYPE	Type of the indexed object

UNIQUENESS	Uniqueness status of the index:  UNIQUE or

NONUNIQUE

TABLESPACE_NAME	Name of the tablespace containing the index

INI_TRANS	Initial number of transactions

MAX_TRANS	Maximum number of transactions

INITIAL_EXTENT	Size of the initial extent

NEXT_EXTENT	Size of secondary extents

MIN_EXTENTS	Minimum number of extents allowed in the

segment

MAX_EXTENTS	Maximum number of extents allowed in the

segment

PCT_INCREASE	Percentage increase in extent size

PCT_FREE	Minimum percentage of free space in ablock

BLEVEL	The depth of the index from its root block to

its leaf blocks. A depth of 1 indicates that the

root block and leaf block are the same.

LEAF_BLOCKS	The number of leaf blocks in the index.

DISTINCT_KEYS	The number of distinct indexed values. For

indexes that enforce UNIQUE and PRIMARY

KEY constraints, this value is the same as the

number of rows in the table (USER_TA

BLES.NUM_ROWS).

AVG_LEAF_BLOCKS_PER_KEY	The average number of leaf blocks in which

each distinct value in the index appears. This

statistic is rounded to the nearest integer. For

indexes that enforce UNIQUE and PRIMARY

KEY constraints, this value is always 1.

 AVG_DATA_BLOCKS_PER_KEY	The average number of data blocks in the

table that are pointed to by a distinct value in

the index. This statistic is the average number

of data blocks that contain rows that contain a

given value for the indexed column(s). This

statistic is rounded to the nearest integer.

CLUSTERING_FACTOR	This statistic represents the amount of order

of the rows in the table based on the values of

the index. If its value is near the number of

blocks, then the table is very well ordered. In

such a case, the index entries in a single leaf

block tend to point to rows in the same data

blocks. If its value is near the number of rows,

then the table is very randomly ordered. In

such a case, it is unlikely that index entries in

the same leaf block point to rows in the same

data blocks.

ALL_IND_COLUMNS	Columns of the indexes on accessible tables

INDEX_OWNER	Index owner

INDEX_NAME	Name of the index

TABLE_OWNER	Table or cluster owner

TABLE_NAME	Table or cluster name

COLUMN_NAME	Column name

COLUMN_POSITION	Position of column within index

COLUMN_LENGTH	Indexed length of the column

ALL_LABELS	A TRUSTED ORACLE view that lists system labels.  For details, see

the Trusted ORACLE7 Server Administrator`s Guide.

ALL_MOUNTED_DBS	A TRUSTED ORACLE view that lists mounted databases  For details,

see the Trusted ORACLE7 Server Administrator`s Guide.

ALL_OBJECTS	Objects accessible to the user

OWNER	Username of the owner of the object

OBJECT_NAME	Name of the object

OBJECT_ID	Object number of the object

OBJECT_TYPE	Type of the object

CREATED	Timestamp for the creation of the object

LAST_DDL_TIME	Timestamp for the last modification of the ob

ject resulting from a DDL command (includ

ing grants and revokes)

TIMESTAMP	Timestamp for the creation of the object (char

acter data)

STATUS	Status of the object: VALID or INVALID

ALL_SEQUENCES	Description of sequences accessible to the user

SEQUENCE_OWNER	 Name of the owner of the sequence

SEQUENCE_NAME	Sequence name

MIN_VALUE	Minimum value of the sequence

MAX_VALUE	Maximum value of the sequence

INCREMENT_BY	Value by which sequence is incremented

CYCLE_FLAG	Does sequence wrap around on reaching limit

ORDER_FLAG	Are sequence numbers generated in order

CACHE_SIZE	Number of sequence numbers to cache

LAST_NUMBER	Last sequence number written to disk.

If a sequence uses caching, the number writ

ten to disk is the last number placed in the

sequence cache. This number is likely to be

greater than the last sequence number that

was used.

ALL_SNAPSHOTS	All snapshots accessible to the user

OWNER	Owner of the snapshot

NAME	The name of the view used by users and ap

plications for viewing the snapshot

TABLE_NAME	The table the snapshot is stored in. This table

has an extra column for the master rowid

MASTER_VIEW	View of the master table, owned by the snap

shot owner, used for refreshes

MASTER_OWNER	Owner of the master table

MASTER	Name of the master table that this snapshot is

a copy of

MASTER_LINK	Database link name to the master site

CAN_USE_LOG	"YES" if this snapshot can use a snapshot log,

"NO" if this snapshot is too complex to use a

log

LAST_REFRESH	Date and time at the master site of the last

refresh

ERROR	The error returned last time an automatic re

fresh was attempted

TYPE	The type of refresh for all automatic refreshes:

COMPLETE, FAST, FORCE

NEXT	The date function used to compute next re

fresh dates

START_WITH	The date function used to compute next re

fresh dates

QUERY	The original query that this snapshot is an

instantiation of

ALL_SOURCE	Text source of all stored objects accessible to the user

ALL_SOURCE	Text source of all stored objects in the data

base

OWNER	Owner of the object

NAME	Name of the object

TYPE	Type of object:  PROCEDURE, PACKAGE,

FUNCTION, PACKAGE BODY

LINE	Line number of this line of source

TEXT	Text source of the stored object

ALL_SYNONYMS	Text source of all stored objects accessible to the user

OWNER	Owner of the synonym

SYNONYM_NAME	Name of the synonym

TABLE_OWNER	Owner of the object referenced by the syn

onym

TABLE_NAME	Name of the object referenced by the syn

onym

DB_LINK	Name of the database link referenced, if any

ALL_TAB_COLUMNS	Columns of all tables, views, and clusters accessible to the user

OWNER	Owner of the table, view or cluster

TABLE_NAME	Table, view, or cluster name

COLUMN_NAME	Column name

DATA_TYPE	Datatype of the column

DATA_LENGTH	Length of the column in bytes

DATA_PRECISION	Decimal precision for NUMBER datatype;

binary precision for FLOAT datatype; NULL

for all other datatypes.

DATA_SCALE	Digits to right of decimal point in a number

NULLABLE	Does column allow NULLs?  Value is 'N' if

there is a NOT NULL constraint on the col

umn or if the column is part of a PRIMARY

KEY.

COLUMN_ID	Sequence number of the column as created

DEFAULT_LENGTH	Length of default value for the column

DATA_DEFAULT	Default value for the column

NUM_DISTINCT	The number of distinct values in each column

of the table.

LOW_VALUE	For tables with more than three rows, the se

HIGH_VALUE	cond-lowest and second-highest values in

the column. For tables with three rows or few

er, the lowest and highest values. These statis

tics are expressed in hexadecimal notation for

the internal representation of the first 32 bytes

of the values. These statistics appear only for

indexed columns.

ALL_TAB_COMMENTS	Comments on tables and vies accessible to the user

OWNER	Owner of the object

TABLE_NAME	Name of the object

TABLE_TYPE	Type of the object

COMMENTS	Comment on the object

ALL_TAB_PRIVS	Grants on objects for which the user or PUBLIC is the grantee

GRANTOR	Name of the user who performed the grant

GRANTEE	Name of the user to whom access is granted

TABLE_SCHEMA	Schema of the object

TABLE_NAME	Name of the object

PRIVILEGE	Privilege on the object

GRANTABLE	YES if the privilege was granted WITH

ADMIN OPTION, otherwise NO

ALL_TAB_PRIVS_MADE	User's grants and grants on user`s objects

GRANTEE	Name of the user to whom access was

granted

OWNER	Owner of the object

TABLE_NAME	Name of the object

GRANTOR	Name of the user who performed the grant

PRIVILEGE	Privilege on the object

GRANTABLE	YES if the privilege was granted WITH

ADMIN OPTION, otherwise NO

ALL_TAB_PRIVS_RECVD	Grants on objects for which the user or PUBLIC is the grantee

GRANTEE	Name of the user to whom access was

granted

OWNER	Owner of the object

TABLE_NAME	Name of the object

GRANTOR	Name of the user who performed the grant

PRIVILEGE	Privilege on the object

GRANTABLE	YES if the privilege was granted WITH

ADMIN OPTION, otherwise NO

ALL_TABLES	Description of tables accessible to the user

OWNER	Owner of the table

TABLE_NAME	Name of the object referenced by the syn

onym

TABLESPACE_NAME	Name of the tablespace containing the table

CLUSTER_NAME	Name of the cluster, if any, to which the table

belongs

PCT_FREE	Minimum percentage of free space in a block

PCT_USED	Minimum percentage of used space in a block

INI_TRANS	Initial number of transactions

MAX_TRANS	Maximum number of transactions

INITIAL_EXTENT	Size of the initial extent in bytes

NEXT_EXTENT	Size of the secondary extents in bytes

MIN_EXTENTS	Minimum number of extents allowed in the

segment

MAX_EXTENTS	Maximum number of extents allowed in the

segment

PCT_INCREASE	Percentage increase in extent size

BACKED_UP	Has table been backed up since last change

NUM_ROWS	Number of rows in the table

BLOCKS	Number of data blocks allocated to the table

EMPTY_BLOCKS	Number of data blocks allocated to the table

that contain no data

AVG_SPACE	Average amount of free space (in bytes) in a

data block allocated to the table

CHAIN_CNT	Number of rows in the table that are chained

fro ne data block to another, or which have

migrated to a new block, requiring a link to

preserve the old rowid

ALL_TRIGGERS	Triggers accessible to the current user

OWNER	Owner of the trigger Owner of the trigger

NAME	Name of the trigger

TYPE	Type of the trigger:  BEFORE ROW, BEFORE

STATEMENT, AFTER ROW, AFTER STATE

MENT

TRIGGERING_STATEMENT	Event that will fire the trigger:  INSERT, UP

DATE, and/or DELETE

TABLE_OWNER	Owner of the table that this trigger is

associated with

TABLE_NAME	Name of the table that this trigger is

associated with

WHEN	The WHEN clause. Must evaluate to TRUE

for TRIGGER_BODY to execute

ENABLED	Whether or not the trigger is enabled:  EN

ABLED or DISABLED

TRIGGER_BODY	The statement(s) executed by the trigger

when it fires

ALL_TRIGGER_COLS	Shows usage of colums in triggers owned by user, on tables owned by user,

or on all triggers if the user has the CREATE ANY TRIGGER privilege

TRIGGER_OWNER	Owner of the trigger

TRIGGER_NAME	Name of the trigger

TRIGGER_OWNER	Owner of the table the trigger is defined on

TABLE_NAME	Table the trigger is defined on

COLUMN_NAME	Name of the column used in the trigger

COLUMN_LIST	Column specified in UPDATE clause:Y/N

COLUMN_USAGE	How the column is used in the trigger. All

applicable combinations of NEW, OLD, IN,

OUT, and IN OUT

ALL_USERS	Information about all users of the database

USERNAME	 Name of the user

USER_ID	 ID number of the user

CREATED	 User creation date

ALL_VIEWS	Text of views accessible to the user

OWNER	Owner of the view

VIEW_NAME	Name of the view

TEXT_LENGTH	Length of the view text

TEXT	View text

AUDIT_ACTIONS	Description table for audit trail action type codes

ACTION	Numeric audit trail action type code

NAME	Name of the type of audit trail action

CAT	Synonym for USER_CATALOG

CHAINED_ROWS	Default table for the ANALYZE LIST CHAINED ROWS command

OWNER_NAME	Table owner

TABLE_NAME	Table name

CLUSTER_NAME	Cluster the table is in, if any

HEAD_ROWID	RowID the chained row is accessed by

TIMESTAMP	Date?time that the ANALYZE command was

issued

 CLU	Synonym for USER_CLUSTERS

CODE_PIECES	Accessed to create the ALL_OBJECT_SIZE, DBA_OBJECT_SIZE, and

USER_OBJECT_SIZE views

CODE_SIZE	Accessed to create the ALL_OBJECT_SIZE, DBA_OBJECT_SIZE, and

USER_OBJECT_SIZE views

COLS	Synonym for USER_TAB_COLUMNS

COLUMN_PRIVILEGES	Grants on colums for which the user is the grantor, grantee, or owner, or PUB

LIC is the grantee

GRANTEE	Name of the user to whom access was

granted

OWNER	Owner of the object

TABLE_NAME	Name of the object

GRANTOR	Name of the user who perfomred the grant

PRIVILEGE	Privilege of the object

GRANTABLE	YES if the privilege was granted with

ADMIN OPTION, otherwise, NO

COLUMN_NAME	Name of the column

GRANTOR	Name of the user who performed the grant

INSERT_PRIV	Permission to insert into the column

UPDATE_PRIV	Permission to update the column

REFERENCES_PRIV	 Permission to reference the column

CREATED	Timestamp for the grant

DBMS_ALERT_INFO	Table of registgered alerts

NAME	Name of the alert

SID	Session ID of a session waiting for this alert

CHANGED	Boolean flag to indicate that an alert has been

signaled.  Y:  Alert signaled.  N:  No alert.

MESSAGE	Optional message passed by the signaler

DBMS_LOCK_	Table of user-allocated locks.

ALLOCATED

NAME	Name of the lock

LOCKID	Lock identifer number

EXPIRATION	Planned lock expiration date (updates when

ever the allocation procedure is run)

DEPTREE	Object dependency tree.  Created by UTLDTREE.SQL. For user SYS, this view

shows shared cursors (and only shared cursors) that depend on the object.  For

all other users, it shows objects other than shared cursors.  (Other users may

access SYS.DEPTREE for information on shared cursors.)

NESTED_LEVEL	Nesting level in the dependency tree

TYPE	Object type

OWNER	Object owner

NAME	Object name

SEQ#	Sequence number in the dependency tree.

Used for ordering queries.  (See also:  the

IDEPTREE view)

DICT	Synonym for DICTIONARY

DICTIONARY	Description of data dictionary tables and views

TABLE_NAME	Name of the object

COMMENTS	Text comment on the object

DICT_COLUMNS	Description of columns in data dictionary tables and views

TABLE_NAME	Name of the object that contains the column

COLUMN_NAME	Name of the column

COMMENTS	Text comment on the column

ERROR_SIZE	Accessed to create the ALL_OBJECT_SIZE, DBA_OBJECT_SIZE, and

USER_OBJECT_SIZE views

EXCEPTIONS	Information on violations of integrith constraints

ROW_ID	Row that caused the violation

OWNER	Owner of the table

TABLE_NAME	Name of the table

CONSTRAINT	Integrity constraint that was violated

GLOBAL_NAME	Contains one row that shows the global name of the current database

GLOBAL_NAME	Global name of the database

IDEPTREE	Indented dependency tree.  Created by UTLDTREE.SQL.  Pre-sorted version

of DEPTREE.

NESTED_LEVEL	Nesting level in the dependency tree

TYPE	Object type

OWNER	Object owner

NAME	Object name

IND	Synonym for USER_INDEXES

INDEX_HISTOGRAM	Contains information from the ANALYZE INDEX VALIDATE STRUCTURE

command

REPEAT_COUNT	Number of times that one or more index keys

is repeated in the table

KEYS_WITH_REPEAT_COUNT	Number of index keys that are repeated that

many times

INDEX_STATS	Stores information from the ANALYZE INDEX VALIDATE STRUCTURE

command

HEIGHT	Height of the B-tree

BLOCKS	Blocks allocated to the segment

NAME	Name of the index

LF_ROWS	Number of leaf rows (values in the index)

LF_BLOCKS	Number of leaf blocks in the B-tree

LF_ROWS_LEN	Sum of the lengths of all the leaf rows

LF_BLK_LEN	Useable space in a leaf block

BR_ROWS	Number of branch rows in the B-tree

BR_BLKS	Number of branch blocks in the B-tree

BR_ROWS_LEN	Sum of the lengths of all the branch blocks in

the B-tree

BR_BLK_LEN	Useable space in a branch block

DEL_LF_ROWS	Number of deleted leaf rows in the index

DEL_LF_ROWS_LEN	Total length of all deleted rows in the index

DISTINCT_KEYS	Number of distinct keys in the index (may

include rows that have been deleted)

MOST_REPEATED_KEY	How many times the most repeated key is

repeated (may include rows that have been

deleted)

BTREE_SPACE	Total space currently allocated in the B-tree

USED_SPACE	Total space that is currently being used in the

B-tree

PCT_USED	Percent of space allocated in the B-tree that is

being used

ROWS_PER_KEY	Average number of rows per distinct key (this

figure is calculated without consideration of

deleted rows)

BLKS_GETS_PER_ACCESS	Expected number of consistent mode block

gets per row. This assumes that a row chosen

at random from the table is being searched for

using the index.

OBJ	Synonym for USER_OBJECTS

RESOURCE_COST	Cost for each resource

RESOURCE_NAME	Name of the resource

UNIT_COST	Cost of the resource

ROLE_ROLE_PRIVS	Information about roles granted to other roles

ROLE	Name of the role

GRANTED_ROLE	Role that was granted

ADMIN_OPTION	Signifies that the role was granted with

ADMIN option

ROLE_SYS_PRIVS	Information about system privileges granted to roles

ROLE	Name of the role

PRIVILEGE	System privilege granted to the role

ADMIN_OPTION	Signifies the grant was with the ADMIN op

tion

ROLE_TAB_PRIVS	Information about table privileges granted to roles

ROLE	 Name of the role

OWNER	 Owner of the object

TABLE_NAME	 Name of the object

COLUMN_NAME	 Name of the column, if applicable

PRIVILEGE	 Object privilege granted to the role

GRANTABLE	YES if the role was granted WITH ADMIN

OPTION, otherwise NO

 SEQ	Synonym for USER_SEQUENCES

SESSION_PRIVS	Privileges that are currently available to the user

PRIVILEGE	Name of the privilege

SESSION_ROLES	Roles that the user currently has enabled

ROLE	 Name of the role

SOURCE_SIZE	Accessed to create the ALL_OBJECT_SIZE, DBA_OBJECT_SIZE, and

USER_OBJECT_SIZE views.

STMT_AUDIT_	Desctiption table for auditing option type codes

OPTION_MAP

OPTION#	Numeric auditing option type code

NAME	Name fo the auditing option

 SYN	Synonym for USER_SYNONYMS

SYSTEM_PRIV	Desctiption table for system privilege codes

ILEGE_MAP

TABLE_PRIVILEGES	Grants on objects for which the user is the grantor, grantee, or owner, orPUB

LIC is the grantee

GRANTEE	 Name of the user to whom access is granted

OWNER	Owner of the object

TABLE_NAME	Name of the object

GRANTOR	Name of the user who performed the grant

SELECT_PRIV	Permission to select from the object

INSERT_PRIV	Permission to insert into the object

DELETE_PRIV	Permission to delete from the object

UPDATE_PRIV	Permission to update the object

REFERENCES_PRIV	Permission to reference the object

ALTER_PRIV	Permission to alter the object

INDEX_PRIV	Permission to create or drop an index on the

object

CREATED	Timestamp for the grant

TABLE_PRIVILEGE_MAP	Description table for access privilege codes

TABS 	Synonym for USER_TABLES

USER_AUDIT_OBJECT 	Audit trail records for statements concerning objects

OS_USERNAME	Operating system logon username of the user

whose actions were audited

USERNAME	Name (not ID number) of the user whose ac

tions were audited

USERHOST	Numeric instance ID for the ORACLE

instance from which the user is accessing the

database

TERMINAL	Identifier for the user's terminal

TIMESTAMP	Timestamp for the creation of the audit trail

entry or logon time for the CONNECT state

ment

OWNER	Creator of object affected by the action

OBJ_NAME	Name of the object affected by the action

ACTION_NAME	Name of the action type corresponding to the

numeric code in ACTION

NEW_OWNER	Owner of the object named in the

NEW_NAME column

NEW_NAME	The new name of an object renamed by a RE

NAME statement

SES_ACTIONS	Session summary (a string of 11 characters,

one for each action type, in the order Alter,

Audit, Comment, Delete, Grant, Index, Insert,

Lock, Rename, Select, and Update; coded -

for none, S for success, F for failure, and B for

both)

COMMENT_TEXT	Text comment on the audit trail entry (in

serted by an application program)

SESSIONID	Numeric ID for each ORACLE session

ENTRYID	Numeric ID for each audit trail entry in the

session

STATEMENTID	Numeric ID for each statement run (astate

ment may cause many actions)

RETURNCODE	ORACLE error code generated by the action

(zero if the action succeeded)

PRIV_USED	System privilege used to exeute the action

OBJECT_LABEL	Optional Trusted ORACLE label associated

with the object being audited

SESSION_LABEL	Trusted ORACLE label associated with the

user session

USER_AUDIT_SESSION	All audit trail records concerning connections and disconnections for the user

OS_USERNAME	Operating system logon user name of the user

whose actions were audited

USERNAME	Name (not ID number) of the user whose ac

tions were audited

USERHOST	Numeric instance ID for the ORACLE

instance from which the user is accessing the

database

TERMINAL	Identifier for the user's terminal

TIMESTAMP	Timestamp for the creation of the audit trail

entry or logon time for the CONNECT state

ment

ACTION_NAME	Name of the action type corresponding to the

numeric code in ACTION

LOGOFF_TIME	Timestamp for user logoff

LOGOFF_LREAD	Logical reads for the session

LOGOFF_PREAD	Physical reads for the session

LOGOFF_LWRITE	Logical writes for the session

LOGOFF_DLOCK	Deadlocks detected during the session

SESSIONID	Numeric ID for each ORACLE session

RETURNCODE	ORACLE error code generated by the action

(zero if the action succeeded)

SESSION_LABEL	Trusted ORACLE label associated with the

user session

USER_AUDIT_STATE	Audit trail entries for the following statements:  GRANT, REVOKE, AUDIT,

MENT	NOAU DIT, and ALTER SYSTEM

OS_USERNAME	Operating system logon username of the user

whose actions were audited

USERNAME	Name (not ID number) of the user whose ac

tions were audited

USERHOST	Numeric instance ID for the ORACLE

instance from which the user is accessing the

database

TERMINAL	Identifier for the user's terminal

IMESTAMP	Timestamp for the creation of the audit trail

entry or logon time for the CONNECT state

ment

OWNER	Creator of object affected by the action

OBJ_NAME	Name of the object affected by the action

ACTION_NAME	Name of the action type corresponding to the

numeric code in ACTION

NEW_NAME	The new name of an object after a RENAME

OBJ_PRIVILEGE	Object privileges granted/revoked by a

GRANT/REVOKE statement

SYS_PRIVILEGE	System privileges granted/revoked by a

GRANT/REVOKE statement

ADMIN_OPTION	 Signifies the role or system privilege was

granted with ADMIN option

GRANTEE	The username of the grantee specified in a

GRANT/REVOKE statement

AUDIT_OPTION	Auditing option set with the AUDIT state

ment

SES_ACTIONS	Session summary (a string of 11 characters,

one for each action type, in the order Alter,

Audit, Comment, Delete, Grant, Index, Insert,

Lock, Rename, Select, and Update; coded -

for none, S for success, F for failure, and B for

both)

COMMENT_TEXT	Text comment on the audit trail entry (in

serted by an application program)

SESSIONID	Numeric ID for each ORACLE session

ENTRYID	Numeric ID for each audit trail entry in the

session

STATEMENTID	Numeric ID for each statement run (astate

ment may cause many actions)

RETURNCODE	ORACLE error code generated by the action

(zero if the action succeeded)

PRIV_USED	System privilege used to exeute the action

SESSION_LABEL	Trusted ORACLE label associated with the

user session

USER_AUDIT_TRAIL	Audit trail entries relevant to the user

OS_USERNAME	Operating system logon username of the user

whose actions were audited

USERNAME	Name (not ID number) of the user whose ac

tions were audited

USERHOST	Numeric instance ID for the ORACLE

instance from which the user is accessing the

database

TERMINAL	Identifier for the user's terminal

TIMESTAMP	Timestamp for the creation of the audit trail

entry or logon time for the CONNECT state

ment

OWNER	Creator of object affected by the action

OBJ_NAME	Name of the object affected by the action

ACTION	Numeric type code corresponding to the ac

tion name

ACTION_NAME	Name of the action type corresponding to the

numeric code in ACTION

NEW_OWNER	The owner of the object named in the

NEW_NAME column

NEW_NAME	The new name of an object renamed by a RE

NAME statement

OBJ_PRIVILEGE	Object privileges granted/revoked by a

GRANT/REVOKE statement

SYS_PRIVILEGE	System privileges granted/revoked by a

GRANT/REVOKE statement

ADMIN_OPTION	Signifies the role or system privilege was

granted with ADMIN option

GRANTEE	The username of the grantee specified in a

GRANT/REVOKE statement

AUDIT_OPTION	Auditing option set with the AUDIT state

ment

SES_ACTIONS	Session summary (a string of 11 characters,

one for each action type, in the order Alter,

Audit, Comment, Delete, Grant, Index, Insert,

Lock, Rename, Select, and Update; coded -

for none, S for success, F for failure, and B for

both)

LOGOFF_TIME	Timestamp for user logoff

LOGOFF_LREAD	Logical reads for the session

LOGOFF_PREAD	Physical reads for the session

LOGOFF_LWRITE	Logical writes for the session

LOGOFF_DLOCK	Deadlocks detected during the session

COMMENT_TEXT	Text comment on the audit trail entry (in

serted by an application program)

SESSIONID	Numeric ID for each ORACLE session

ENTRYID	Numeric ID for each audit trail entry in the

session

STATEMENTID	Numeric ID for each statement run (astate

ment can cause many actions)

RETURNCODE	ORACLE error code generated by the action

(zero if the action succeeded)

PRIV_USED	System privilege used to exeute the action

OBJECT_LABEL	Optional Trusted ORACLE label associated

with the object being audited

SESSION_LABEL	Trusted ORACLE label associated with the

user session

USER_CATALOG	Tables, views, synonyms, and sequences owned by the user

TABLE_NAME	Name of the object

TABLE_TYPE	Type of the object

USER_CLUSTERS	Description of user's own clusters

CLUSTER_NAME	Name of the cluster

TABLESPACE_NAME	Name of the tablespace containing thecluster

PCT_FREE	Minimum percentage of free space in a block

PCT_USED	Minimum percentage of used space in a block

KEY_SIZE	Estimated size of cluster key plus associated

rows

INI_TRANS	Initial number of transactions

MAX_TRANS	Maximum number of transactions

INITIAL_EXTENT	Size of the initial extent in bytes

NEXT_EXTENT	Size of secondary extents in bytes

MIN_EXTENTS	Minimum number of extents allowed in the

segment

MAX_EXTENTS	Maximum number of extents allowed in the

segment

PCT_INCREASE	Percentage increase in extent size

AVG_BLOCKS_PER_KEY	Number of blocks in the table divided by

number of hash keys

CLUSTER_TYPE	Type of cluster: B-tree index or hash

FUNCTION	Hash function used for a hash cluster

HASHKEYS	Number of hash keys for a hash cluster

USER_CLU_COLUMNS	Mapping of table columns to cluster columns

CLUSTER_NAME	Cluster name

CLU_COLUMN_NAME	Key column in the cluster

TABLE_NAME	Clustered table name

TAB_COLUMN_NAME	Key column in the table

USER_COL_COMMENTS	Comments on columns of user's tables and views

TABLE_NAME	Object name

COLUMN_NAME	Column name

COMMENTS	Comment on the column

USER_COL_PRIVS	Grants on columns for which the user is the owner, grantor, or grantee.

GRANTEE	Name of the user to whom access was

granted

OWNER	Owner of the object

TABLE_NAME	Name of the object

COLUMN_NAME	Name of the column

GRANTOR	Name of the user who performed the grant

PRIVILEGE	Privilege on the column

GRANTABLE	YES if the privilege was granted WITH

ADMIN OPTION, otherwise NO

USER_COL_PRIVS_MADE	All grants on columns of objects owned by the use

GRANTEE	Name of the user to whom access wasgranted

TABLE_NAME	Name of the object

COLUMN_NAME	Name of the column

GRANTOR	Name of the user who performed the grant

PRIVILEGE	Privilege on the column

GRANTABLE	YES if the privilege was granted WITH

ADMIN OPTION, otherwise NO

USER_COL_PRIVS_RECD	Grants on columns for which the user is the grantee

OWNER	Username of the owner of the object

TABLE_NAME	Name of the object

COLUMN_NAME	Name of the column

GRANTOR	Name of the user who performed the grant

PRIVILEGE	Privilege on the column

GRANTABLE	YES if the privilege was granted WITH

ADMIN OPTION, otherwise NO

USER_CONSTRAINTS	Constraint definitions on user's tables

OWNER	Owner of the constraint definition

CONSTRAINT_NAME	Name associated with the constraint defini

tion

CONSTRAINT_TYPE	Type of constraint definition:  C (check

constraint on a table), P (primary key), unique

key), R (referential integrity), V(with check

option, on a view)

TABLE_NAME	Name associated with table with constraint

definition

SEARCH_CONDITION	Text of search condition for table check

R_OWNER	Owner of table used in referential constraint

R_CONSTRAINT_NAME	Name of unique constraint definition for ref

erenced table

STATUS	Status of constraint: ENABLED or DISABLED

USER_CONS_COLUMNS	Information about columns in constraint definitions owned by the user

OWNER	Owner of the constraint definition

CONSTRAINT_NAME	Name associated with the constraint defini

tion

TABLE_NAME	Name associated with table with constraint

definition

COLUMN_NAME	Name associated with column specified in the

constraint definition

POSITION	Original position of column in definition

USER_DB_LINKS	Database links owned by the user

DB_LINK	Name of the database link

USERNAME	Name of user to log on as

PASSWORD	Password for logon

HOST	SQL*Net string for connect

CREATED	Creation time of the database link

USER_DEPENDENCIES	Dependencies to and from a user's objects

NAME	Name of the object

TYPE	Type of object:  PROCEDURE, PACKAGE,

FUNCTION, PACKAGE BODY

REFERENCED_OWNER	Owner of the parent object

REFERENCED_NAME	Name of the parent object

REFERENCED_TYPE	Type of the parent object:  PROCEDURE,

PACKAGE, FUNCTION, PACKAGE BODY

REFERENCED_LINK_OWNER	Owner of the link to the parent object (if re

mote)

REFERENCED_LINK_NAME	Name of the link to the parent object (if re

mote)

USER_ERRORS	Current errors on all stored objects in the database

NAME	Name of the object

TYPE	Type of object:  PROCEDURE, PACKAGE,

FUNCTION, PACKAGE BODY

LINE	Line number at which this error occurs

POSITION	Position in the line at which this error occurs

TEXT	Text of the error

USER_EXTENTS	Extents of the segments owned by the user

SEGMENT_NAME	Name of the segment associated with theex

tent

SEGMENT_TYPE	Type of the segment

TABLESPACE_NAME	Name of the tablespace containing theextent

EXTENT_ID	Extent number in the segment

BYTES	Size of the extent in bytes

BLOCKS	Size of the extent in ORACLE blocks

USER_FREE_SPACE	Free extents in tablespaces accessible to the user

TABLESPACE_NAME	Name of the tablespace containing theextent

FILE_ID	ID number of the file containing the extent

BLOCK_ID	Starting block number of the extent

BYTES	Size of the extent in bytes

BLOCKS	Size of the extent in ORACLE blocks

USER_IND_COLUMNS	Columns of the user's indexes or on user's tables

INDEX_NAME	Index name

TABLE_NAME	Table or cluster name

COLUMN_NAME	Column name

COLUMN_POSITION	Position of column within index

COLUMN_LENGTH	Indexed length of the column

USER_INDEXES	Description of the user's own indexes

INDEX_NAME	Name of the index

TABLE_OWNER	Owner of the indexed object

TABLE_NAME	Name of the indexed object

TABLE_TYPE	Type of the indexed object

UNIQUENESS	Uniqueness status of the index: UNIQUE or

NONUNIQUE

TABLESPACE_NAME	Name of the tablespace containing the index

INI_TRANS	Initial number of transactions

MAX_TRANS	Maximum number of transactions

INITIAL_EXTENT	Size of the initial extent in bytes

NEXT_EXTENT	Size of secondary extents in bytes

MIN_EXTENTS	Minimum number of extents allowed in the

segment

MAX_EXTENTS	Maximum number of extents allowed in the

segment

PCT_INCREASE	Percentage increase in extent size

PCT_FREE	Minimum percentage of free space in ablock

BLEVEL	The depth of the index from its root block to

its leaf blocks. A depth of 1 indicates that the

root block and leaf block are the same.

LEAF_BLOCKS	The number of leaf blocks in the index.

DISTINCT_KEYS	The number of distinct indexed values. For

indexes that enforce UNIQUE and PRIMA RY

KEY constraints, this value is the same as the

number of rows in the table (USER_TA

BLES.NUM_ROWS).

AVG_LEAF_BLOCKS_PER_KEY	The average number of leaf blocks in which

each distinct value in the index appears. This

statistic is rounded to the nearest integer. For

indexes that enforce UNIQUE and PRIMARY

KEY constraints, this value is always 1.

AVG_DATA_BLOCKS_PER_KEY	The average number of data blocks in the

table that are pointed to by a distinct value in

the index. This statistic is the average number

of data blocks that contain rows that contain a

given value for the indexed column(s). This

statistic is rounded to the nearest integer.

CLUSTERING_FACTOR	This statistic represents the amount of order

of the rows in the table based on the values of

the index.

If its value is near the number of blocks, then

the table is very well ordered. In such a case,

the index entries in a single leaf block tend to

point to rows in the same data blocks.

If its value is near the number of rows, then

the table is very randomly ordered. In such a

case, it is unlikely that index entries in the

same leaf block point to rows in the same data

blocks.

USER_OBJ_AUDIT_OPTS	Auditing options for user's own tables and views

OBJECT_NAME	Name of the object

OBJECT_TYPE	Type of the object:  TABLE or VIEW

ALT	Auditing ALTER WHENEVER SUCCESSFUL

/ UNSUCCESSFUL

AUD	Auditing AUDIT WHENEVER SUCCESSFUL

/ UNSUCCESSFUL

COM	Auditing COMMENT WHENEVER SUC

CESSFUL / UNSUCCESSFUL

DEL	Auditing DELETE WHENEVER SUC

CESSFUL / UNSUCCESSFUL

GRA	Auditing GRANT WHENEVER SUC

CESSFUL / UNSUCCESSFUL

IND	Auditing INDEX WHENEVER SUCCESSFUL

/ UNSUCCESSFUL

INS	Auditing INSERT WHENEVER SUC

CESSFUL / UNSUCCESSFUL

LOC	Auditing LOCK WHENEVER SUCCESSFUL

/ UNSUCCESSFUL

REN	Auditing RENAME WHENEVER SUC

CESSFUL / UNSUCCESSFUL

SEL	Auditing SELECT WHENEVER SUC

CESSFUL / UNSUCCESSFUL

UPD	Auditing UPDATE WHENEVER SUC

CESSFUL / UNSUCCESSFUL

REF	Auditing REFERENCES WHENEVER SUC

CESSFUL / UNSUCCESSFUL

EXE	Auditing EXECUTE WHENEVER SUC

CESSFUL / UNSUCCESSFUL

USER_OBJECTS	Objects owned by the user

OBJECT_NAME	Name of the object

OBJECT_ID	Object number of the object

OBJECT_TYPE	Type of the object

CREATED	Timestamp for the creation of the object

LAST_DDL_TIME	Timestamp for the last modification of the ob

ject resulting from a DDL command (in clud

ing grants and revokes)

TIMESTAMP	Timestamp for the creation of the object (char

acter data)

STATUS	Status of the object: VALID or INVALID

USER_OBJECT_SIZE	User's PL/SQL objects

NAME	Name of the object

TYPE	Type of the object: PROCEDURE, PACKAGE,

or PACKAGE BODY

SOURCE_SIZE	Size of source code in bytes

PARSED_SIZE	Size of parsed code in bytes

CODE_SIZE	Size of compiled code in bytes

ERROR_SIZE	Size of error messages in bytes

USER_RESOURCE_	Displays the resource limits for the current user

LIMITS

RESOURCE_NAME	Name of the resource

LIMIT	Limit placed on this resource

USER_ROLE_PRIVS	Roles granted to the user

USERNAME	Name of the user, or PUBLIC

GRANTED_ROLE	Name of the role granted

ADMIN_OPTION	Signifies the role was granted with ADMIN

option

USER_SEGMENTS	Storage allocation for all database segments

SEGMENT_NAME	Name, if any, of the segment

SEGMENT_TYPE	Type of segment:  TABLE, CLUSTER, INDEX,

ROLLBACK, DEFERRED ROLLBACK, TEM

PORARY, CACHE

TABLESPACE_NAME	Name of the tablespace containing theseg

ment

BYTES	Size, in bytes, of the segment

BLOCKS	Size, in ORACLE blocks, of the segment

EXTENTS	Number of extents allocated to the segment

INITIAL_EXTENT	Size of the initial extent in ORACLE blocks

NEXT_EXTENT	Size of the next extent to be allocated in

ORACLE blocks

MIN_EXTENTS	Minimum number of extents allowed in the

segment

MAX_EXTENTS	Maximum number of extents allowed in the

segment

PCT_INCREASE	Percent by which to increase the size of the

next extent to be allocated

FREELISTS	Number of process freelists allocated to this

segment

FREELIST_GROUPS	Number of freelist groups allocated to thsi

segment

USER_SEQUENCES	Description of the user's own sequences

SEQUENCE_NAME	SEQUENCE name

MIN_VALUE	Minimum value of the sequence

MAX_VALUE	Maximum value of the sequence

INCREMENT_BY	Value by which sequence is incremented

CYCLE_FLAG	Does sequence wraparound on reachinglimit

ORDER_FLAG	Are sequence numbers generated in order

CACHE_SIZE	Number of sequence numbers to cache

LAST_NUMBER	Last sequence number written to disk.  If a

sequence uses caching, the number written to

disk is the last number placed in the sequence

cache. This number is likely to be greater than

the last sequence number that was actually

used.

This value is not continuously updated dur

ing databse operation. It is intended for use

afterr a warmstart or impor

USER_SOURCE	Text source of all stored objects in the database

NAME	Name of the object

TYPE	Type of object:  PROCEDURE, PACKAGE,

FUNCTION, PACKAGE BODY

LINE	Line number of this line of source

TEXT	Text source of the stored object

USER_SNAPSHOTS	Snapshots the user can view

OWNER	Owner of the snapshot

NAME	The name of the view used by users and ap

plications for viewing the snapshot

TABLE_NAME	The table the snapshot is stored in. This table

has an extra column for the master rowid

MASTER_VIEW	View of the master table, owned by the snap

shot owner, used for refreshes

MASTER_OWNER	Owner of the master table

MASTER	Name of the master table that this snapshot is

a copy of

MASTER_LINK	Database link name to the master site

CAN_USE_LOG	YES if this snapshot can use a snapshot log,

NO if this snapshot is too complex to use a log

LAST_REFRESH	Date and time at the master site of the last

refresh

ERROR	The error returned last time an automatic re

fresh was attempted

TYPE	The type of refresh for all automatic refreshes:

COMPLETE, FAST, FORCE

NEXT	The date function used to compute next re

fresh dates

START_WITH	The date function used to compute next re

fresh dates

QUERY	The original query that this snapshot is an

instantiation of

USER_SNAPSHOT_LOGS	All snapshot logs owned by the user

LOG_OWNER	Owner of the snapshot log

MASTER	Name of the master table which the log re

cords changes of

LOG_TABLE	Log table that holds the rowids and time

stamps of rows which changed in the master

table

LOG_TRIGGER	An after-row trigger on the master which in

serts rows into the log

CURRENT_SNAPSHOTS	The date the snapshot of the master was last

refreshed

USER_SYNONYMS	The user's private synonyms

SYNONYM_NAME	Name of the synonym

TABLE_OWNER	Owner of the object referenced by thesyno

nym

TABLE_NAME	Name of the object referenced by thesynonym

DB_LINK	Database link referenced in a remotesynonym

USER_SYS_PRIVS	System privileges granted to the user

USERNAME	Name of the user, or PUBLIC

PRIVILEGE	System privilege granted to the user

ADMIN_OPTION	Signifies the privilege was granted with

ADMIN option

USER_TAB_COLUMNS	Columns of user's tables, views, and clusters

TABLE_NAME	Table, view, or cluster name

COLUMN_NAME	Column name

DATA_TYPE	Datatype of the column

DATA_LENGTH	Maximum length of the column in bytes

DATA_PRECISION	Decimal precision for NUMBER datatype;

binary precision for FLOAT datatype; NULL

for all other datatypes.

DATA_SCALE	Digits to right of decimal point in a number

NULLABLE	Does column allow NULLs?  Value is 'N' if

there is a NOT NULL constraint on the col

umn or if the column is part of a PRIMARY

KEY.

COLUMN_ID	Sequence number of the column as created

DEFAULT_LENGTH	Length of default value for the column

DATA_DEFAULT	Default value for the column

NUM_DISTINCT	The number of distinct values in each column

of the table

LOW_VALUE HIGH_VALUE	For tables with more than three rows, the se

cond-lowest and second-highest values in

the column. For tables with three rows or few

er, the lowest and highest values. These statis

tics are expressed in hexadecimal notation for

the internal representation of the first 32 bytes

of the values. These statistics appear only for

indexed columns.

USER_TAB_COMMENTS	Comments on the tables and views owned by the user

TABLE_NAME	Name of the object

TABLE_TYPE	Type of the object:  TABLE or VIEW

COMMENTS	Comment on the object

USER_TAB_PRIVS	Grants on objects for which the user is the owner, grantor, or grantee

GRANTEE	Name of the user to whom access was

granted

OWNER	Owner of the object

TABLE_NAME	Name of the object

GRANTOR	Name of the user who performed the grant

PRIVILEGE	Privilege on the object

GRANTABLE	YES if the privileges was granted WITH

ADMIN OPTION, otherwise NO

USER_TAB_PRIVS_MADE	All grants on objects owned by the user

GRANTEE	Name of the user to whom access was

granted

TABLE_NAME	Name of the object

GRANTOR	Name of the user who performed the grant

PRIVILEGE	Privilege on the object

GRANTABLE	YES if the privilege was granted WITH

ADMIN OPTION, otherwise NO

USER_TAB_PRIVS_RECD	Grants on objects for which the user is the grantee

OWNER	Owner of the object

TABLE_NAME	Name of the object

GRANTOR	Name of the user who performed the grant

PRIVILEGE	Privilege on the object

GRANTABLE	YES if the privilege was granted WITH

ADMIN OPTION, otherwise NO

USER_TABLES	Description of the user's own tables

TABLE_NAME	Name of the table

TABLESPACE_NAME	Name of the tablespace containing the table

CLUSTER_NAME	Name of the cluster, if any, to which the table

belongs

PCT_FREE	Minimum percentage of free space in a block

PCT_USED	Minimum percentage of used space in a block

INI_TRANS	Initial number of transactions

MAX_TRANS	Maximum number of transactions

INITIAL_EXTENT	Size of the initial extent in bytes

NEXT_EXTENT	Size of secondary extents in bytes

MIN_EXTENTS	Minimum number of extents allowed in the

segment

MAX_EXTENTS	Maximum number of extents allowed in the

segment

PCT_INCREASE	Percentage increase in extent size

BACKED_UP	Has table been backed up since lastmodifica

tion

NUM_ROWS	The number of rows in the table

BLOCKS	The number of data blocks allocated to the

table

EMPTY_BLOCKS	The number of data blocks allocated to the

table that contain no data

AVG_SPACE	The average amount of free space (in bytes) in

a data block allocated to the table

CHAIN_CNT	The number of rows in the table that are

chained from one data block to another, or

which have migrated to a new block, requir

ing a link to preserve the old rowid.

AVG_ROW_LEN	The average length of a row in the table in

bytes

USER_TABLESPACES	Description of accessible tablespaces

TABLESPACE_NAME	Tablespace name

INITIAL_EXTENT	Default initial extent size

NEXT_EXTENT	Default incremental extent size

MIN_EXTENTS	Default minimum number of extents

MAX_EXTENTS	Default maximum number of extents

PCT_INCREASE	Default percent increase for extent size

STATUS	Tablespace status:  ONLINE, OFFLINE, or

INVALID (tablespace has been dropped)

USER_TRIGGERS	Description of the user's triggers

NAME	Name of the trigger

TYPE	Type of the trigger: BEFORE STATEMENT,

AFTER STATEMENT, BEFORE ROW, AF TER

ROW

TRIGGERING_STATEMENT	Event that will fire the trigger

TABLE_OWNER	Owner of the table that this trigger is

associated with

TABLE_NAME	Name of the table that this trigger is

associated with

WHEN	WHEN clause. Must evaluate to TRUE for the

TRIGGER_BODY to execute

ENABLED	Whether or not the trigger is enabled:  EN

ABLED or DISABLED

TRIGGER_BODY	The statement(s) executed by the trigger

when it fires

USER_TRIGGERS_COLS	Shows usage of columns in triggers owned by user or on one of user's tables

TRIGGER_OWNER	Owner of the trigger

TRIGGER_NAME	Name of the trigger

TABLE_OWNER	Owner of the table the trigger is defined on

TABLE_NAME	Table the trigger is defined on

COLUMN_NAME	Name of the column used in the trigger

COLUMN_LIST	Column specified in UPDATE clause:  Y/N

COLUMN_USAGE	How the column is used in the trigger. All

applicable combinations of NEW, OLD, IN,

OUT, and IN OUT.

USER_TS_QUOTAS	Tablespace quotas for the user

TABLESPACE_NAME	Tablespace name

BYTES	Number of bytes charged to the user

MAX_BYTES	User's quota in bytes, orUNLIMITED

BLOCKS	Number of ORACLE blocks charged to the

user

MAX_BLOCKS	User's quota in ORACLE blocks, or UN

LIMITED

USER_USERS	Information about the current user

USERNAME	Name of the user

USER_ID	ID number of the user

DEFAULT_TABLESPACE	Default tablespace for data

TEMPORARY_TABLESPACE	Default tablespace for temporary tables

CREATED	User creation date

USER_VIEWS	Text of views owned by the user

VIEW_NAME	Name of the view

TEXT_LENGTH	Length of the view text

TEXT	View text

________________________________________

The Dynamic Performance Tables

The ORACLE RDBMS contains a set of underlying "tables" that are maintained by the RDBMS and accessible to the DBA user SYS. These tables are called dynamic performance tables because they are continuously updated while a database is open and in use, and their contents relate primarily to performance.

Although these tables appear to be regular database tables, they are not. Like ROWIDs and ROWNUMs, these tables may be selected from, but never updated or altered.

The file CATALOG.SQL contains definitions of the views and public synonyms for the dynamic performance tables. You must run CATALOG.SQL to create these views and synonyms.

Views created on the dynamic performance tables are identified by the prefix V_$, and public synonyms for these views have the prefix V$. DBAs or users should only access the V$ objects, not the V_$ objects.

In general, these views are not intended for direct access by DBAs or users. Rather, the dynamic performance tables are used by SQL*DBA, which is the primary interface for accessing information about system performance.

Suggestion: Once the instance is started, the V$ views are accessible. The database does not have to be mounted or open. As a result, the V$LOG view can be used to identify logfiles needed for recovery.

Access to the Dynamic Performance Tables

After installation, only username SYS has accessto the dynamic performance tables. However, access to these tables is required for any user needing to view the MONITOR displays available in SQL*DBA.

To make information in these tables accessible to other database users, a DBA can create views on individual tables and then grant users SELECT access to the views.

Alternatively, the file MONITOR.SQL can be run to grant access to PUBLIC on all of the dynamic performance tables. The drawback to running this file is that you may not want all database users to have equal access to all of this information. Thus, the selective method of creating views and granting access may be preferable. See your installation or user's guidefor details on running MONITOR.SQL

Description of Individual Tables

This section lists the columns and public synonyms for the dynamicperformance tables.

Warning:  Information about the dynamic performance tables is presented for completeness only; this information does not imply a commitment to support these tables in the future.

V$ACCESS	Shows objects in the database that are currently locked and the sessions that

are  accessing them.

SID	VARCHAR2	Session number that is accessing

an object

OWNER	VARCHAR2	Owner of the object

OBJECT	VARCHAR2	Name of the object

OB_TYP	NUMBER	Type of identified for the object

V$ARCHIVE	Information on archive logs for each thread in the database system.  (Each

row provides information for one thread.)

GROUP#	NUMBER	Logfile group number

THREAD#	NUMBER	logfile thread number

SEQUENCE#	NUMBER	Logfile sequence number

CURRENT	VARCHAR2	Archive log currently in use

FIRST_CHANGE#	NUMBER	First SCN stored in the current log

V$BACKUP	Backup status of all online datafiles

FILE#	NUMBER	File identifier

STATUS	VARCHAR2	File status: NOT ACTIVE, AC

TIVE (backup in progress), OF

LINE NORMAL, or descripion of

an error

CHANGE#	NUMBER	System change number when

backup started

TIME	NUMBER	Time the backup started

V$BGPROCESS	Describes the background processes

PADDR	RAW(4)	Address of the process state object

NAME	VARCHAR2	Name of this background process

DESCRIPTION	VARCHAR2	Description of the background

process

ERROR	NUMBER	Error encountered

V$CIRCUIT	Information about virtual circuits (user connections to the database through

dispatchers and servers).

CIRCUIT	RAW(4)	Circuit address

DISPATCHER	RAW(4)	Current dispatcher process ad

dress

SERVER	RAW(4)	Current server process address

WAITER	RAW(4)	Address of server process that is

waiting for the (currently busy)

circuit to become available

SADDR	RAW(4)	Address os session bound to the

circuit

STATUS	VARCHAR2	Status of the circuit:

BREAK (currently interrupted),

EOF (about to be removed)

OUTBOUND (an outward link to

a remote database),

NORMAL (normal circuit into the

local database)

QUEUE	VARCHAR2	Queue the circuit is currently on:

COMMON (on the common

queue, waiting to be picked up by

a server process),

DISPATCHER (waiting for the

dispatcher),

SERVER (currently being serv

iced),

OUTBOUND (waiting to establish

an outbound connection,

NONE (idel circuit)

MESSAGE0	NUMBER	Size in bytes of the messages in

the first message buffer

MESSAGE1	NUMBER	Size in bytes of the messages in

the second message buffer

MESSAGES	NUMBER	Total number of messages that

have gone through this circuit

BYTES	NUMBER	Total number of bytes that have

gone through this circuit

BREAKS	NUMBER	Total number of breaks (interrup

tions) for this circuit

V$DATABASE	Database information from teh control file

NAME	VARCHAR2	Name of the database

CREATED	VARCHAR2	Creation date

LOG_MODE	VARCHAR2	Archive log mode:

NOARCHIVELOG or ARCHIVE

LOG

CHECKPOINT_	NUMBER	Last SCN checkpointed

CHANGE#

ARCHIVE_	NUMBER	Last SCN archived

CHANGE#

V$DATAFILE	Datafile information from the control file

FILE#	NUMBER	File identification number

STATUS	VARCHAR2	Type of file (system or user) and

its status. Values: OFFLINE, SYS

OFF, ONLINE, SYSTEM, RE

COVER

CHECK	NUMBER	SCN at last checkpoint

POINT_CHANGE#

BYTES	NUMBER	Size in bytes

NAME	VARCHAR2	Name of the file

V$DBFILE	All data files making up the database.  This view is retained for historical

compatibility.  Use of V$DATAFILE is recommended instead.

FILE#	NUMBER	File identifier

NAME	VARCHAR2	Name of file

V$DB_OBJECT_CACHE	Shows database objects that are cached in the library cache.  Objects include

tables, indexes, clusters, synonym definitions, PL/SQL procedures and pack

ages, and triggers.

OWNER	VARCHAR2	Owner of the object

NAME	VARCHAR2	Name of the object

DB_LINK	VARCHAR2	Database link name, if any

NAMESPACE	VARCHAR2	Library cache namespace of the

object:

TABLE/PROCEDURE, BODY,

TRIGGER, INDEX, CLUSTER,

OBJECT

TYPE	VARCHAR2	Type of the object;

INDEX, TABLE, CLUSTER, VIEW,

SET, SYNONYM, SEQUENCE,

PROCEDURE, BUNCTION,

PACKAGE, PACKAGE BODY,

TRIGGER, CLASS, OBJECT,

USER, DBLINK

SHARABLE_MEM	NUMBER	Amount of sharable memory in

the share pool sonsumed by the

object loaded. This count also

increses when an object has been

invalidated

LOADS	NUMBER	Number of tiems the objectr has

been loaded. this count also

increases when an objecrt has

been invalidated

EXECUTIONS	NUMBER	Total number of times this object

has been executed

LOCKS	NUMBER	Number of users currently locking

this object

PINS	NUMBER	Number of users currently

pinning this object

V$DISPATCHER	Information on the dispatcher processes

NAME	VARCHAR2	Name of the dispatcher process

NETWORK	VARCHAR2	Network protocol supported by

this dispatcher. For example, TCP

or DECNET.

PADDR	RAW(4)	Process address

STATUS	VARCHAR2	Dispatcher status:

WAIT (idle)

SEND (sending a message),

CONNECT (establishing a con

nection),

DISCONNECT (handling a dis

conect request),

BREAK (handling a break),

OUTBOUND (establishing an out

bound connection)

ACCEPT	VARCHAR2	WHether this dispatcher is accept

ing new connections: YES, NO

MESSAGES	NUMBER	Number of messages processed by

this dispatcher

BYTES	NUMBER	Size in bytes of messages pro

cessed by this dispatcher

BREAKS	NUMBER	Number of breaks occurring in

this connection

OWNED	NUMBER	Number of circuits owned by this

dispatcher

CREATED	NUMBER	Number of circuits created by this

dispatcher

IDLE	NUMBER	Total idle time for this dispatcher,

in hundredths of a second

BUSY	NUMBER	Total busy time for this dispatcher,

in hundredths of a second

V$ENABLEDPRIVS	Which privileges are enabled

PRIV_NUMBER	NUMBER	Numeric identifier of enabled

privileges

V$FILESTAT	Information about file read/write statistics

FILE#	NUMBER	Number of the file

PHYRDS	NUMBER	Number of physical reads done

PHYWRTS	NUMBER	Number of physical writes done

PHYBLKRD	NUMBER	Number of physical blocks read

PHYBLKWRT	NUMBER	Number of physical blocks writ

ten

READTIM	NUMBER	Time spent doing reads if the pa

rameter TIMED_STATISTICS is

TRUE; 0 if FALSE

WRITETIM	NUMBER	Time spent doing writes if the pa

rameter TIMED_STATISTICS is

TURE; 0 if FALSE

V$FIXED_TABLE	Shows all fixed tables, views, and derived tables in the database

NAME	VARCHAR2	Name of the object

OBJECT_ID	NUMBER	Identifier of the fixed object

TYPE	VATCHAR2	Object type: TABLE, VIEW

V$INSTANCE	State of the current instance

KEY	VARCHAR2	Name of state variable, from teh

table below

VALUE	NUMBER	Value of the state variable

Instance State Variable	Value

RESTRICTED MODE	0 (False), 1 (True)

SHUTDOWN PENDING	0 (False), 1 (True)

STARTUP TIME-JULIAN	Start time and date in Julian format

STARTUP TIME-SECONDS	Number of seconds since midnight on

the startup date

V$LATCH	Information about each type of latch. (The rows of this table and the rows of

V$LATCHNAME correspond one-to-one.)

ADDR	RAW(4)	Address of latch object

LATCH#	NUMBER	Ltch number

LEVEL#	NUMBER	Latch level

GETS	NUMBER	Number of times obtained wait

MISSES	NUMBER	Number of times obtained with

wait but failed first try

SLEEPS	NUMBER	Number of times slept when

wanted wait

IMMEDIATE_	NUMBER	Number of times obtained with

GETS	not wait

IMEDIATE_	NUMBER	Number of times failed to get with

MISSES	no wait

V$LATCHHOLDER	Information about the current latch holders.

PID	NUMBER	Identifier of process holding the

latch

LADDR	RAW(4)	Latch address

V$LATCHNAME	The decoded latch names for the latches shown in table V$LATCH.  (The

rows of this table and the rows of V$LATCH correspond one-to-one.)

LATCH#	NUMBER	Latch nmber

NAME	VARCHAR2	Latch name

V$LIBRARYCACHE	Statistics on library cache management

NAMESPACE	NUMBER	Library cache namespace:

SQL, AREA,

TABLE/PROCEDURE, BODY,

TRIGGER, INDEX, CLUSTER,

OBJECT, PIPE

GETS	NUMBER	Number of times the systme

requests handles to library objects

belonging to this namespace

GETHITS	NUMBER	Number of times the handles are

already allocated in the cache. If

the handle is not already

allocated, it is a miss. the handle

is then allocated and inserted into

the cache.

GETHIRRATIO	NUMBER	Nubmer of GWETHITS divided

by GETS. Values close to 1

indicate that most of the handles

the system has tried to get are

cached.

PINS	NUMBER	Number of times the system issue

spin requests for objects in the

cache in order to access them

PINHITS	NUMBER	Number of times that objects the

system is pinning and access are

already allocated and initialized

in the cache. Otherwise, it is a

miss, and the system has to

allocate it in the cahce and

initialize it with data queried

from the database or generate the

data.

PINHITRATIO	NUMBER	Number of PINHITS divided by

number of PINS. Values close to

1q indicate that most of the objects

the system has tried to pin and

access have been cached.

RELOADS	NUMBER	Number of times that library

objects have to be reintialized and

reloaded with data becauase they

have been aged out or invalidated

INVALIDATIONS	NUMBER	Number of tiems that

non-persistent library objects (like

share SQL areas have been

invalidated

V$LICENSE	Information about license limits

SESSIONS_MAX	NUMBER	Maximum number of cuocurrent

user sessions allowed for the

instance

SESSIONS_	NUMBER	Warning limit for concurrent user

WARNING	sessions for the instance

SESSIONS_	NUMBER	Current number of concurrent

CURRENT	user sessions

SESSION_	NUMBER	Highest nubmer of concurrent

HIGHWATER	user sessions sicne the instance

started

USERS_MAX	NUMBER	Maximum number of named us

ers allowed for the database

V$LOADCSTAT	SQL*Loader statistics compiled during the execution of a direct load.  These

statistics apply to the whole load.  Any select against this table results in "no

rows returned" since you cannot load data and do a query at the same time.

READ	NUMBER	Number of records read

REJECTED	NUMBER	Number of records rejected

TDISCARD	NUMBER	Total number of discards during

the load

NDISCARD	NUMBER	Number of discards from the cur

rent file

SAVEDATA	NUMBER	Whether or not save data points

are used

V$LOADSTAT	SQL*Loader statistics compiled during the execution of a direct load.  These

statistics apply to the current table.  Any select against this table results in "no

rows returned" since you cannot load data and do a query at the same time.

LOADED	NUMBER	Number of records loaded

REJECTED	NUMBER	Number of records rejected

FAILWHEN	NUMBER	Number of records that failed to

meet any WHEN clause

ALLNULL	NUMBER	Number of records that were com

pletely numm and wee therefore

not loaded

LEFT2SKIP	NUMBER	Number of records yet to skip

during a continued load

V$LOCK	Information about locks and resources.  Does not include DDL locks.

ADDR	NUMBER	Address of lock state object

KADDR	NUMBER	Address of lock

SID	NUMBER	Identifier of process holding the

lock

TYPE	NUMBER	Resource type (see following

table)

ID1	NUMBER	Resource identifier #1

ID2	NUMBER	Resource identifier #2

LMODE	NUMBER	Lock mode held: 1 (null), 2 (row

share), 3 (row exclusive), 4 (share),

5 Share row exclusive), 6 (exlu

sive)

REQUEST	NUMBER	Lock mode requested (same val

ues as LMODE)

The following locks are obtained by user applications.  Any process which is blocking others is likely to be holding one of these locks.

User Lock Type	Description

RW	Row wait enqueue lock

TM	DML enqueue lock

TX	Transaction enqueue lock

UL	User supplied lock

The following system locks are held for extremely short periods of time:

System Lock Type	Description

BL	Buffer hash table instance lock

CF	Cross-instance function invocation instance lock

CI	Control file schema global enqueue lock

CS	Control file schema global enqueue lock

DF	Data file instance lock

DM	Mount/startup db primary/secondary instance

lock

DR	Distributed recovery process lock

DX	Distributed transaction entry lock

FI	SGA open-file information lock

FS	File set lock

IR	Instance recovery srealization globbal enqueue

lock

IV	Library cache invalidation instance lock

LA..LP	Library cache lock instance lock (A..P=name

space)

LS	Log start/log switch enqueue lock

MB	Master buffer hash table instance lock

MM	Mount definition global enqueue lock

MR	Media recovery lock

PA..PZ	Library cache pin instance lock (A..Z=name

space)

QA..QZ	Row cache instance lock (A..Z=cache)

RE	USE_ROW_ENQUEUE enforcement lock

RT	Redo thread global enqueue lock

SC	System commit number instnace lock

SH	System commit number high wat4er mark en

queue lock

SN	Sequence number instance lock

SQ	Sequence number enqueue lock

ST	Space transaction enqueue lock

SV	Sequence number value lock

TA	Generic enqueue lock

TD	DDl enqueue lock

TE	Extend-segment enqueue lock

TS	Temporary segment enqueue lock )ID2=0)

TS	New block allocation enqueue lock (ID2=1)

TT	Temporary table enqueue lock

UN	User name lock

WL	Being-Written redo log instance lock

WS	Write-atomic-log-switch golbal enqueue lock

V$LOG	Log file information for a control file

GROUP#	NUMBER	Log group number

THREAD#	NUMBER	Log thread number

SEQUENCE#	NUMBER	Log sequence number

BYTES	NUMBER	Size of the log in bytes

MEMBERS	NUMBER	Number of members in the log

group

ARCHIVED	VARCHAR2	Lrchive status: TRUE, FALSE

FIRST_CHANGE#	NUMBER	Lowest SCN in the log

FIRST_TIME	VARCHAR2	Time of first SCN in the log

V$LOGFILE	Information about redo log files

GROUP#	NUMBER	Redo log group identifier number

STATUS	VARCHAR2	Status of this log member:

INVALID (file is inaccessible),

STALE (file`s contents are incom

plete),

DELETED (file is no longer used),

or

blank (file is in use)

MEMBER	VARCHAR2	Redo log member name

V$LOGHIST	Log history from the control file.  This view is retained for historical compati

bility.  Use of V$LOG_HISTORY is recommended instead.

THREAD#	NUMBER	Log thread number

SEQUENCE#	NUMBER	Log sequence number

FIRST_CHANGE#	NUMBER	Lowest SCN in the log

FIRST_TIME	VARCHAR2	Time of first SCN in the log

SWITCH_	NUMBER	SCN at which the log switch oc

CHANGE#	curred; one more than highest

SCN in the log

V$LOG_HISTORY	Archived log names for all logs in the log history

THREAD#	NUMBER	Thread number of the archived

log

SEQUENCE#	NUMBER	Sequence number of the archived

log

TIME	NUMBER	Time of first entry (lowest SCN) in

the log

LOW_CHANGE#	NUMBER	Lowest SCN in the log

HIGH-CHANGE#	NUMBER	Highest SCN in the log

ARCHIVE_NAME	VARCHAR2	Name of file when archived, using

the RCHIVE_FORMAT

initialization parameter

V$NLS_PARAMETERS	Current values of NLS parameters

NAME	VARCHAR2	Parameter name:

NLS_LANGUAGE, NLS_SORT,

NLS_TERRITORY, NLS_CHAR

ACTERSET,

NLS_CURRENCY,

NLS_ISO_CURRENCY,

NLS_NUMERIC_CHARACTERS,

NLS_DATE_FORMAT,

NLS_DATE_LANGUAGE

VALUE	VARCHAR2	NLS parameter value

V$OPEN_CURSOR	Cursors that each user session currently has opened and parsed

SADDR	RAW	Session address

USER_NAME	VARCHAR2	User that is logged into the ses

sion

ADDRESS	RAW	Used with HASH_VALUE to

uniquely identify the SQL state

ment being executed in the ses

sion

HASH_VALUE	NUMBER	Used with aADDRESS to unique

ly identify the SQL statement be

ing executed in the session

SQL_TEXT	VARCHAR2	First 60 characters of the SQL

statement that is parsed into the

open sursor

V$PARAMETER	Information about current parameter values

NUM	NUMBER	Prameter number

NAME	VARCHAR2	Paremeter name

TYPE	NUMBER	Parameter type

VALUE	VARCHAR2	Parameter value

ISDEFAULT	VARCHAR2	Default value in use: TRUE,

FALSE

V$PROCESS	Information about currently active processes

ADDR	RAW(4)	Address of process state object

PID	NUMBER	ORACLE process identifier

SPID	VARCHAR2	Operating system process identifi

er

USERNAME	VARCHAR2	Operating system process user

name. Any Two-Task user com

ing across the network had "-T"

appended to the username.

SERIAL#	NUMBER	Process serial number

TERMINAL	VARCHAR2	Operating system terminal identi

fier

PROGRAM	VARCHAR2	Program in progress

BACKGROUND	VARCHAR2	1 for a background process; null

for a normal process

LATCHWAIT	VARCHAR2	Address of latch waiting for; null

if none

V$QUEUE	Information on the multi-threaded message queues

PADDR	RAW(4)	Addresses pf the process that

owns the queue

TYPE	VARCHAR2	Type of queue:

COMMON (processed by servers),

OUTBOUND (used by remote

servers),

DISPATCHER.

QUEUED	NUMBER	Number of items in the queue

WAIT	NUMBER	Number of items in the queue

have waited. Divide by TOTALQ

for average wait per item.

TOTALQ	NUMBER	Total number of items that have

ever been in the queue

V$RECOVERY_LOG	Archived logs needed to complete media recovery.  This information is

derived from the log history (V$LOG_HISTORY).  The amount of informa

tion available is limited by the setting of the MAX_LOG_HISTORY initial

ization parameter.

THREAD#	NUMBER	Thread number of the archived

log

SEQUENCE#	NUMBER	Sequence number of the archived

log

TIME	NUMBER	Time of first entry (lowest SCN) in

the log

ARCHIVE_NAME	VARCHAR2	Name of file when archived, using

the naming convention specified

by the LOG_ARCHIVE_FORMAT

initialoization parameter

V$RECOVER_FILE	Status of files needing media recovery

FILE#	NUMBER	File identifier number

ONLINE	VARCHAR2	Online status: ONLINE, OFFLINE

ERROR	VARCHAR2	Why the file needs to be recov

ered:

NULL if reason unknown, or OF

FLINE NORMAL if recovery not

needed

CHANGE#	NUMBER	SCN where recovery must start

TIME	VARCHAR2	Time of SCN where recovery must

start

V$REQDIST	Histogram of request times, divided into 12 buckets, or ranges of times.  The

time ranges grow exponentially as a function of the bucket number.

BUCKET	NUMBER	Bucket nubmer: 0..11; the maxi

mum time for each bucket is

(4*2^N)/100 seconds

COUNT	NUMBER	Count of request whose total time

to complete (exclusing wait time)

falls in this range.

V$RESOURCE	Information about resources

ADDR	RAW(4)	Address of resource object

TYPE	VARCHAR2	Resource type

ID1	NUMBER	Resource identifier #1

ID2	NUMBER	Resource identifier #2

V$ROLLNAME	Names of all online rollback segments

USN	NUMBER	Rollback ("undo") segment num

ber

NAME	VARCHAR2	Rollback segment name

V$ROLLSTAT	Statistics for all online rollback segments

USN	NUMBER	Rollback segment number

EXTENTS	NUMBER	Number of rollback extents

RESIZE	NUMBER	Size in bytes of rollback segment

WRITES	NUMBER	Number of bytes written to roll

back segment

XACTS	NUMBER	Number of active transactions

GETS	NUMBER	Number of header gets

WAITS	NUMBER	Number of header waits

OPTSIZE	NUMBER	Optimal size of rollback segment

HWMSIZE	NUMBER	High watert mark of roolback seg

ment size

SHRINKS	NUMBER	Number of times rollback seg

ment shrank, eliminating one or

more additional extents each time

WRAPS	NUMBER	Number of times rollback seg

ment wraps from one extent to

another

EXTENDS	NUMBER	Number of times rollback seg

ment was extended to have a enw

extent

AVESHRINK	NUMBER	Total size of freed extents divided

by number of shrinks

AVEACTIVE	NUMBER	Current average size of active ex

tents, where "active" extents have

uncommitted transaction data

STATUS	VARCHAR2	ONLINE if the segment is online,

or PENDING OFFLINE if the seg

ment is going offline but some ac

tive (distributed) transactions are

using the rolback segment. When

the transactions complete, the seg

ment goes offline.

V$ROWCACHE	Statistics for data dictionary activity.  (Each row contains statistics for one data

dictionarly cache.)

CACHE#	NUMBER	Row cache ID number

TYPE	Parent or subordinate row cache

type

SUBORDINATE#	NUMBER	Subordinate set number

PARAMETER	VARCHAR2	Name of the INIT.ORA parameter

that determiens the number of en

tries in the data distionary cache

COUNT	NUMBER	Total number of entries in the

cache

USAGE	NUMBER	Number of cache entries that con

tain valid data

FIXED	NUMBER	Number of fixed entries in the

cache

GETS	NUMBER	Total number of requests for in

formation on the data object

GETMISSES	NUMBER	Number of data requests resulting

in cache misses

SCANS	NUMBER	Number of scan requests

SCANMISSES	NUMBER	Nmber of times a wscan failed to

find the data in the cache

SCANCOMPLETES	NUMBER	For a list of subordinate entreis,

the number of times the list was

scaned completely

MODIFICATIONS	NUMBER	Number of times a scan failed to

find the data in the cache

FLUSHES	NUMBER	Number of times slushed to disk

V$SESSION	Session information for each current session

SADDR	RAW(4)	Session address

SID	NUMBER	Sesison identifier

SERIAL#	NUMBER	Session serial numver. Used to

uniquely identify a session`s ob

jects. Gurantees that session-level

commands are applied to the cor

rect session objects in the even

that the session ends and another

session begins with the same ses

sion ID.

AUDSID	NUMBER	AUditing session ID

PADDR	RAW(4)	Address of the process that owns

this session

USER#	NUMBER	ORACLE user identifier

USERNAME	VARCHAR2	ORACLE username

COMMAND	NUMBER	Command in progress; see the

table on the next page

TADDR	VARCHAR2	Address of transaction state object

LOCKWAIT	VARCHAR2	Address of lock waiting for; null if

non

STATUS	VARCHAR2	Status of the session:

ACTIVE, INACTIVE, Killed

SERVER	VARCHAR2	Server type:

DEDICATED, SHARED, PSUE

DO, NONE

SCHEMA#	NUMBER	Schema user identifier

SCHEMANAME	VARCHAR2	Schema user name

OBUSER	VARCHAR2	Operating system client user

name

PROCESS	VARCHAR2	Operating system client process

ID

MACHINE	VARCHAR2	Operating system machine name

TERMINAL	VARCHAR2	Operating system terminal name

PROGRAM	VARCHAR2	Operating system program name

TYPE	VARCHAR2	Session type

SQL_ADDRESS	RAW	Used with SQL_HASH_VALUE to

identify the SQL statement that is

currently being executed

SQL_HASH_	NUMBER	Used with SQL_ADDRESS to

VALUE	identify the SQL statement that is

currently being executed

Command 	Command

Number

1	CREATE TABLE

2	INSERT

3	SELECT

4	CREATE CLUSTER

5	ALTER CLUSTER

6	UPDATE

7	DELETE

8	DROP

9	CREATE INDEX

10	DROP INDEX

11	ALTER INDEX

12	DROP TABLE

13	---

14	---

15	ALTER TABLE

16	---

17	GRANT

18	REVOKE

19	CREATE SYNONYM

20	DROP SYNONYM

21	CREATE VIEW

22	DROP VIEW

23	---

24	---

25	---

26	LOCK TABLE

27	NO OPERATION

28	RENAME

29	COMMENT

30	AUDIT

31	NOAUDIT

32	CREATE EXTERNAL DATABASE

33	DROP EXTERNAL DATABASE

34	CREATE DATABASE

35	ALTER DATABASE

36	CREATE ROLBACK SEGMENT

37	ALTER ROLLBACK SEGMENT

38	DROP ROLLBACK SEGMENT

39	CREATE TABLESPACE

40	ALTER TABLESPACE

41	DROP TABLESPACE

42	ALTER SESSION

43	ALTER USER

44	COMMIT

45	ROLLBACK

46	SAVEPOINT

V$SESSION_STAT	Lists the resources or events that active sessions are waiting for

SID	NUMBER	Session identifier

SEQ#	NUMBER	Sequence number that uniquely

identifies this wait. Incremente for

each wait.

EVENT	VARCHAR2	Resource or event the session is

waiting for

P1TEXT	VARCHAR2	Description of first additional pa

rameter

P1	VARCHAR2	First additional parameter

P2TEXT	VARCHAR2	Description of second parameter

P2	VARCHAR2	Second additional parameter

P3TEXT	VARCHAR2	Description of third parameter

P3	VARCHAR2	Third additional parameter

WAIT_TIME	NUMBER	A non-zero value is the session's

last wait time. A zero value means

the session is currently waiting.

V$SESSTAT	For each current session, the current statistics values

SID	NUMBER	Sesison identifier

STATISTIC#	NUMBER	Statistic number (identifier)

VALUE	NUMBER	Statistic value

V$SESS_IO	For each current session, the current statistics values

SID	NUMBER	Session identifier

BLOCK_GETS	NUMBER	Block gets for this session

CONSISTENT_	NUMBER	Consisten gets for this session

GETS

PHYSICAL_	NUMBER	Physical reads for this session

READS

BLOCK_	NUMBER	Block changes for this session

CHANGES

CONSISTENT_	NUMBER	Consistent changes for this ses

CHANGES	sion

V$SGA	Summary information on the System Global Area

NAME	VARCHAR2	SGA component group

VALUE	NUMBER	Memory size in bytes

V$SGASTAT	Detailed information on the System Global Area

NAME	VARCHAR2	SGA component name

BYTES	NUMBER	Memory size in byes

V$SHARED_SERVER	Information on the shared server processes

NAME	VARCHAR2	name of the server

PADDR	RAW(4)	Server`s process address

STATUS	VARCHAR2	Server status:

EXEC (executing SQL),

WAIT (SEND) (waiting to send

date to user),

WAIT (COMON) (idel; waiting for

a user request),

WAIT (RESET) (waiting for a cir

cuit to reset after a break),

QUIT (terminating)

MESSAGES	NUMBER	Number of messages processed

BYTES	NUMBER	Total number of bytes in all mes

sages

BREAKS	NUMBER	number of breaks

CIRCUIT	RAW(4)	Address of circuit currently being

serviced

IDLE	NUMBER	Total idel time in hundredths of a

second

BUSY	NUMBER	Total busy time in hundredths of a

second

REQUEST	NUMBER	total number of requests taken

from the common queue in this

server's lifetime

V$SQL_AREA	Statistics on the shared cursor cache.  Each row has statistics on one shared

cursor

SQL_TEXT	VARCHAR2	Text pf tje SQL statement requir

ing the cursor, or the PL/SQL

anonymous code

SHARABLE_MEM	NUMBER	Amount of memory in bytes that

is sharable between users

PRESISTENT_	NUMBER	Amount of per-user memory in

MEM	bytes that persists for the life of

the cursor

RUNTIME_MEM	NUMBER	Amount of per-user memory, in

bytes, that is needed only during

execution

SORTS	NUMBER	Number of sorts performed by the

SQL statement

VERSION_COUNT	NUMBER	Number of different versions of

this cursor. The same SQL test

might be used by different users,

each on their own version of a

table (for example, "SELECT*from

EMP" by SCOTT and JONES,

when they each have their own

version of EMP). In that case, mul

tiple versions of the cursor would

exist.

LOADED_	NUMBER	Versions of the cursor that arecur

VERSIONS	rently fully loeaded, with no parts

aged out

OPEN_VERSIONS	NUMBER	Number of versions that some

user has an open sursor on

USERS_OPENING	NUMBER	number of users that currently

have this SQL statement parsed in

an open cursor

EXECUTIONS	NUMBER	Total number of times this SQL

statement has been executed

USERS_	NUMBER	Number of users that are current

EXECUTING	ly executing this cursor

LOADS	NUMBER	Number of times the cursor has

been loaded. After the body of the

cursor has been aged out of the

cache while the text of the SQL

statement remained in it, or after

the cursor is invalidated

FIRST_	VARCHAR2	Time at which the cursor was first

LOAD_TIME	loaded into the SGA

INVALIDATIONS	NUMBER	Number of times the contents of

the cursor have been invalidated.

For exmple: because tables refer

enced in the cursor are dropped,

validated, or indexed

PARSE_CALLS	NUMBER	Number of times users executed a

parse call for this cursor

DISK_READS	NUMBER	Number of disk blocks read by

this cursor and all cursors caused

to be exeecuted by this cursor

BUFFER_GETS	NUMBER	Used of buffers gotten (in any

mode) by this cursor and all cur

sors caused to be executed by this

cursor.

ADDRESS	RAW	Used together with HASH_VAL

UE to select the full text of the

SQL statement from V$$SQLTEXT

HASH_VALUE	NUMBER	Used together with ADDRESS to

select the full text of the SQL state

ment from V$SQLTEXT

V$SQLTEXT	The text of SQL statements belonging to shared SQL cursors in teh SGA

ADDRESS	RAW	Used with HAS-VALUE to

uniquely identify a cached cursor

HAS_VALUE	NUMBER	Used with ADDRESS to uniquely

identify a chached cursor

PIECE	NUMBER	Number used to order the pieces

of SQL text

SQL_TEXT	VARCHAR2	A column containing one piece of

the SQL text

V$STATNAME	Decoded statistic names for the statistics shown in the V$SESSTAT table

STATISTIC#	NUMBER	Statistic number

NAME	VARCHAR2	Statistic name

CLASS	NUMBER	Statistic class:

1 (User), 2 (redo), 4 (Enqueue), 8

(Cache)

V$SYSLABEL	A Trusted ORACLE view that lists system labels.  For details, see the Trusted

ORACLE7 Server Administrator's Guide.

V$SYSSTAT	The current system-wide value for each statistic in table V$SESSTAT

STATISTIC#	NUMBER	Statistic number

NAME	VARCHAR2	Statistic name

CLASS	NUMBER	Statistic class:

1 (User), 2 (redo), 4 (Enqueue), 8

(Cache)

VALUE	NUMBER	Statistic value

V$THREAD	Thread information from the control file

THREAD#	NUMBER	Thread number

STATUS	VARCHAR2	Thread status: OPEN, CLOSED

ENABLED	VARCHAR2	Enabled status:

DISABLED,

(enabled)) PRIVATE, or

(enabled)PUBLIC

GROUPS	NUMBER	Number of log groups assigned to

this thread

INSTANCE	VARCHAR2	Instance name, if available

OPEN_TIME	VARCHAR2	Last time the thread was opened

CURRENT_	NUMBER	Current log group

GROUP#

SEQUENCE#	Sequence number of current log

CHECKPOINT_	VARCHAR2	SCN at last checkpoint

CHANGE#

CHECKPOINT_	NUMBER	Time of last checkpoint

TIME

V$TIMER	The current time in hundredths of seconds

HSECS	NUMBER	Time in hundredths of a second

V$TRANSACTION	Information about transactions

ADDR	RAW(4)	Address of transaction stat object

SCNBASE	NUMBER	First part of the system change

number, invalid  if  inactive

SCNWRAP	NUMBER	Second part of the system change

number; invalid  if  inactive

XIDUSN	NUMBER	Rollback (undo) segment number;

invalid if inactive

XIDSLOT	NUMBER	Slot number; invalid if inactive

XIDSQN	NUMBER	Sequence number; invalid if inac

tive

UBADBA	NUMBER	Database block address for roll

back data; invalid if inactive

UBASQN	NUMBER	Sequence number for rollback

data; invalid if inactive

UBAREC	NUMBER	Record number for rollback data;

invalid if inactive

V$TYPE_SIZE	Sizes of various database components for use in estimating data block capac

ity

COMPONENT	VARCHAR2	Component name, such as seg

ment or buffer header

TYPE	VARCHAR2	Component type

DESCRIPTION	VARCHAR2	Description of component

SIZE	NUMBER	Size of component

V$VERSION	Version numbers of one core library components in the ORACLE Server.

There is one row for each component.

BANNER	VARCHAR2	Component name and version

number

V$WAITSTAT	Block contention statistics.  This table is only updated when timed statistics

are enabled.

CLASS	VARCHAR2	Class of block subject to conten

tion

COUNT	NUMBER	Number of waits by this OPERA

TION for this CLASS of block

TIME	NUMBER	Sum of all wait times for all the

waits by this OPERATION for this

CLASS of block


APPENDIX E. NATIONAL LANGUAGE SUPPORT

This appendix describes features that enable ORACLE applications to operate with multiple languages using conventions specified by the application user. Topics include:

•	specifying character sets

•	specifying default language-dependent behavior

•	date and number formats

•	using NLS parameters in SQL functions

________________________________________

Specifying Character Sets

When a client application operates with a terminal that uses a different character set than the database, the client application's characters must be converted to the database character set, and vice versa. This conversion is performed automatically and is transparent to the client application. The character set used by the client application is defined by the NLS_LANG parameter.

Character Set Conversion

Replacement characters may be defined for specific characters as part of a character set definition. Where a specific replacement character is not defined, a default replacement character is used. To avoid the use of replacement characters when converting from client to database character set, the latter should be a superset (or equivalent) of all the client character sets.

Storing Data in Multi-Byte Character Sets

Width specifications of the character datatypes CHAR and VARCHAR2 refer to bytes, not characters. Hence, the specification CHAR(20) in a table definition allows 20 bytes for storing character data.

If the database character set is single byte, the number of characters and number of bytes will be the same. If the database character set is multi-byte, there will in general be no such correspondence. A character may consist of one or more bytes, depending on the specific multi-byte encoding scheme and whether shift-in/shift-out control codes are present. Hence, column widths must be chosen with care to allow for the maximum possible number of bytes for a given number of characters.

________________________________________

Specifying Default Language-Dependent Behavior

This section describes NLS_LANGUAGE and NLS_TERRITORY, the initialization parameters that specify the default language-dependent behavior for a session.

NLS_LANGUAG Parameter

Messages used by the Server are stored in binary-format files that are placed in the ora_rdbms directory, or equivalent. (See your installation or user's guide for the location on your system.) Multiple versions of these files can exist, one for each supported language, using the filename convention:

<product_id><language_id>.MSB

For example, the file containing the Server messages in French is called ORAF.MSB, `F' being the language abbreviation used for French.

________________________________________

Date and Number Formats

Several format masks are provided with the TO_CHAR, TO_DATE, and TO_NUMBER functions to format dates and numbers according to the relevant conventions.

Date Formats

A format element RM (Roman Month) returns a month as a Roman numeral. Both uppercase and lowercase can be specified, using RM and rm respectively. For example, for the date 7 Sep 1992, `DD-rm-YY' returns `07-ix-92' and `DD-RM-YY' returns `07-IX-92'.

Warning: 	The MON and DY format masks explicitly support month and day abbreviations that may not be three characters in length. For example, the abbreviations `Lu' and `Ma' can be specified for the French `Lundi' and `Mardi', respectively.

 Week and Day Number Conventions

The week numbers returned by the WW format mask are calculated according to the algorithm int((day-jan1)/7). This week number algorithm does not follow the ISO standard (2015, 1976-06-15).

To support the ISO standard, a format element IW is provided that returns the ISO week number. In addition, format elements, I IY IYY and IYYY, equivalent in behavior to the format elements Y YY YYY YYYY, return the year relating to the ISO week number.

In the ISO standard, the year relating to an ISO week number can be different from the calendar year. For example, 1st Jan 1988 is in ISO week number 53 of 1987. A week always starts on a Monday and ends on a Sunday.

•	If January 1 falls on a Friday, Saturday, or Sunday, then the week including January 1 is the last week of the previous year because most of the days in the week belong to the previous year.

•	If January 1 falls on a Monday, Tuesday, Wednesday, or Thursday, then the week is the first week of the new year because most of the days in the week belong to the new year.

For example, January 1, 1991, is a Tuesday, so Monday, December 31, 1990, to Sunday, January 6, 1991, is week 1. Thus the ISO week number and year for December 31, 1990 is 1, 1991. To use the ISO week number, you must use the format mask `IW' for the week number and one of the `IY' formats for the year. See the ORACLE7 Server SQL Language Reference Manual for more information on using date format masks.

Number Formats

Several additional format elements are provided for formatting numbers:

•	D (Decimal) returns the decimal character

•	G (Group) returns the group separator

•	L (Local currency) returns the local currency symbol

•	C (international Currency) returns the international currency symbol

•	RN (Roman Numeral) returns the number as its roman numeral equivalent

For Roman numerals, both uppercase and lowercase can be specified, using RN and rn respectively. The number to be converted must be an integer in the range 1 to 3999.

________________________________________

Using NLS Parameters in SQL Functions

All character functions support both single-byte and multi-byte characters. Except where explicitly stated, character functions operate character-by-character, rather than byte-by-byte.

All SQL functions whose behavior depends on NLS conventions allow NLS parameters to be specified. These functions are:

•	TO_CHAR

•	TO_DATE

•	TO_NUMBER

•	NLS_UPPER

•	NLS_LOWER

•	NLS_INITCAP

•	NLSSORT

Explicitly specifying the optional NLS parameters for these functions allows the function evaluations to be independent of the NLS parameters in force for the session. This feature may be important for SQL statements that contain numbers and dates as string literals.

For example, the following query is only evaluated correctly if the language being used for dates is American:

SELECT ENAME FROM EMP

WHERE HIREDATE > '1-JAN-91'

Such a query can be made independent of the current date language using:

SELECT ENAME FROM EMP

WHERE HIREDATE > TO_DATE('1-JAN-91','DD-MON-YY',

   'NLS_DATE_LANGUAGE = AMERICAN')

In this way, language-independent SQL statements can be defined where necessary. For example, such statements may be necessary when string literals appear in SQL statements used in views, CHECK constraints, or triggers.

Default Specifications

When evaluating views and triggers, default values for NLS function parameters are taken from the values currently in force for the session. When evaluating CHECK constraints, default values are set by the NLS parameters that were specified at database creation.

Specifying Parameters

The syntax used to specify NLS parameters in SQL functions is:

'parameter = value'

The following NLS parameters may be specified:

•	NLS_DATE_LANGUAGE

•	NLS_NUMERIC_CHARACTERS

•	NLS_CURRENCY

•	NLS_ISO_CURRENCY

•	NLS_SORT

Only certain NLS parameters are valid for particular SQL functions, as follows:

•	TO_DATE: 	NLS_DATE_LANGUAGE

•	TO_NUMBER: 	NLS_NUMERIC_CHARACTERS,

NLS_CURRENCY,

NLS_ISO_CURRENCY

•	TO_CHAR: 	NLS_DATE_LANGUAGE,

NLS_NUMERIC_CHARACTERS,

NLS_CURRENCY,

NLS_ISO_CURRENCY

•	NLS_UPPER: 	NLS_SORT

•	NLS_LOWER: 	NLS_SORT

•	NLS_INITCAP: 	NLS_SORT

•	NLSSORT : 	NLS_SORT

Examples of the use of NLS parameters are:

TO_DATE ('1-JAN-89', 'DD-MON-YY',

   'nls_date_language = American')

TO_CHAR (hiredate, 'DD/MON/YYYY',

   'nls_date_language = French')

TO_NUMBER ('13.000,00', '99G999D99',

   'nls_numeric_characters = ''.,''')

TO_CHAR (sal, '9G999D99L', 'nls_numeric_characters = ''.,''

   nls_currency = ''Dfl ''')

TO_CHAR (sal, '9G999D99C', 'nls_numeric_characters = '',.''

   nls_iso_currency = Japan')

NLS_UPPER (ename, 'nls_sort = Austrian')

NLSSORT (ename, 'nls_sort = German')

Note: For some languages, various lowercase characters correspond to a sequence of uppercase characters, or vice versa. As a result, the output from NLS_UPPER, NLS_LOWER, and NLS_INITCAP can differ from the length of the input.

Unacceptable Parameters

Note that NLS_LANGUAGE and NLS_TERRITORY are not accepted as parameters. Only NLS parameters that explicitly define the specific data items required for unambiguous interpretation of a format are accepted. NLS_DATE_FORMAT is also not accepted as a parameter for the reason described below.

If an NLS parameter is specified in TO_CHAR, TO_NUMBER,  or TO_DATE, a format mask must also be specified as the second parameter. For example, the following specification is legal:

TO_CHAR (hiredate, 'DD/MON/YY', 'nls_date_language = French')

These are illegal:

TO_CHAR (hiredate, 'nls_date_language = French')

TO_CHAR (hiredate, 'nls_date_language = French',

   'DD/MON/YY')

This restriction means that a date format must always be specified if an NLS parameter is used in a TO_CHAR or TO_DATE function. As a result, NLS_DATE_FORMAT is not a valid NLS parameter for these functions.

CONVERT Function

The SQL function CONVERT allows for conversion of character data betweencharacter sets. The full description of CONVERT can be found in the ORACLE7 Server SQL Language Reference Manual

The CONVERT function converts the binary representation of a character string in one character set to another. It uses exactly the same technique as described previously for the conversion between database and client character sets. Hence, it uses replacement characters and has the same limitations. The syntax for CONVERT is:

where src_char_set is the source and dest_char_set is the destination character set.

NLSSORT Function

The NLSSORT function replaces a character string with the equivalent sort string used by the linguistic sort mechanism. For a binary sort, the sort string is the same as the input string. The linguistic sort technique operates by replacing each character string with some other binary values, chosen so that sorting the resulting string produces the desired sorting sequence. When a linguistic sort is being used, NLSSORT returns the binary values used to replace the original string.

 String Comparisons in a WHERE clause

NLSSORT allows applications to perform string matching that follows alphabetic conventions. Normally, character strings in a WHERE clause are compared using the characters' binary values. A character is "greater than" another if it has a higher binary value in the database character set. Since the sequence of characters based on their binary values may not match the alphabetic sequence for a language, such comparisons often do not follow alphabetic conventions. For example, if a column (COL1) contains the values ABC, ABZ, BCD and Ä BC in the ISO 8859/1 8-bit character set, the following query:

SELECT COL1 FROM TAB1 WHERE COL1 > 'B'

returns both BCD and Ä BC since Ä  has a higher numeric value than B. However, in German, an Ä  is sorted alphabetically before B. Such conventions are language dependent even when the same character is used. In Swedish, an Ä  is sorted after Z. Linguistic comparisons can be made using NLSSORT in the WHERE clause, as follows:

WHERE NLSSORT(<col>) <comparison operator> NLSSORT(<comparison string>)

Note that NLSSORT has to be used on both sides of the comparison operator. For example:

SELECT COL1 FROM TAB1 WHERE NLSSORT(COL1) > NLSSORT('B')

If a German linguistic sort is being used, this does not return strings beginning with Ä  since in the German alphabet Ä  comes before B. If a Swedish linguistic sort is being used, such names are returned since in the Swedish alphabet Ä  comes after Z.

 Controlling an ORDER BY Clause

If a linguistic sorting sequence is in use, then NLSSORT is implicitly used on each character item in the ORDER BY clause. As a result, the sort mechanism (linguistic or binary) used for an ORDER BY is transparent to the application. However, if the NLSSORT function is explicitly specified for a character item in an ORDER BY item, then the implicit NLSSORT is not done.

In other words, the NLSSORT linguistic replacement is only applied once, not twice. The NLSSORT function is generally not needed in an ORDER BY clause, when the default sort mechanism is a linguistic sort. However, when the default sort mechanism is BINARY, then a query such as:

SELECT ENAME FROM EMP

ORDER BY ENAME

will use a binary sort. A German linguistic sort can be obtained using:

SELECT ENAME FROM EMP

ORDER BY NLSSORT(ENAME, 'NLS_SORT = GERMAN')


APPENDIX F. OPERATING SYSTEM SPECIFIC INFORMATION

This Guide occasionally refers to other ORACLE manuals that contain detailed information for using ORACLE on a specific operating system. These ORACLE manuals are often called installation or user's guides, although the exact name may vary on different operating systems. Throughout this Guide, references to these manuals are marked with the icon shown in the left margin.

This appendix lists all the references in this guide to operating-system- specific ORACLE manuals, and lists the O/S dependent initialization parameters. If you are using ORACLE on multiple operating systems, this appendix can help you ensure that your applications are portable across these operating systems.

Operating system specific topics are listed alphabetically with page numbers of sections that discuss these topics.

Topic	Page

Parameter files

USER_DUMP_DEST	B - 3, B - 4

SQL scripts	D - 2

MONITOR.SQL location	D - 38

UTLDTREE.SQL	9 - 2

CATPROC.SQL 	7 - 2, 8 - 3

UTLXPLAN.SQL	B - 14

Server messages file	E - 2