< previous page page_307 next page > < previous page page_308 next page > Page 308 Table 8-7. Other Hints (continued) Hint Description NOCACHE(table_name) This is the opposite of CACHE, and tells Oracle to place blocks at the least recently used end of the buffer cache, where they will be cleared out as soon as possible. PUSH_SUBQ Tells Oracle to evaluate nonmerged subqueries as soon as possible during query execution. If you expect the subquery to eliminate a large number of rows, this can result in a performance improvement. Where to Find More Tuning Information Tuning Oracle SQL is a complex subject. The information in this chapter serves only to give you a brief overview of some of the features Oracle provides to help you during the tuning process. There is a lot of other information out there that you should avail yourself of. To start with, read the manual. The Oracle8 Server Tuning manual contains a great deal of tuning information, though some of it is more oriented towards tuning the database server itself rather than tuning individual SQL statements. The Server Tuning manual contains information on Oracle hints, the use of EXPLAIN PLAN, and the TKPROF utility. TKPROF is a bit difficult to use, but can provide a great deal more information about the cost of a query than you will get with EXPLAIN PLAN. There are two good books on Oracle tuning I can recommend. One is Oracle Performance Tuning, 2nd edition, by Mark Gurry and Peter Corrigan (O'Reilly & Associates, 1996). The other is Oracle SQL High-Performance Tuning, by Guy Harrison (Prentice-Hall, 1997). Guy Harrison's book is almost entirely focused on tuning SQL statements, as opposed to tuning the server, and it contains a great deal of helpful information for database programmers. < previous page page_308 next page > < previous page page_309 next page > Page 309 9 The Product User Profile In this chapter: What Is the Product User Profile? Using the Product User Profile In addition to the standard database security Oracle provides and enforces for all database objectstables, views, and the likeOracle also provides an application security scheme for SQL*Plus. This allows you to control the specific commands a SQL*Plus user is allowed to execute. At the core of the SQL*Plus application security scheme is the product user profile. What is the Product User Profile? The product user profile is an Oracle table, owned by the SYSTEM user, that contains a list of SQL*Plus command restrictions by user. The table may contain role restrictions as well. The name of this table used to be PRODUCT_USER_PROFILE. Now it is just PRODUCT_PROFILE, but a synonym named PRODUCT_USER_PROFILE exists to ensure backwards compatibility. Why Does the Product User Profile Exist? Primarily, the product user profile enables you to give end users access to SQL*Plus for reporting and ad-hoc query purposes, yet restrict them from using SQL*Plus commands such as INSERT, DELETE, etc., that might damage production data. Real-world applications typically implement a large number of business rules, edit checks, and even security at the application level rather than within the database. Modifying the data using an ad-hoc tool, such as SQL*Plus, bypasses the rules and puts data integrity at risk. Because of this, it's usually important to ensure that data is modified through the application, where the rules can be enforced. < previous page page_309 next page > < previous page page_310 next page > Page 310 If you give people an application that requires a database username and password, and those people also have access to SQL*Plus, it won't be too long before some curious and adventurous soul will figure out that the same userid and password that works for the application will also work for SQL*Plus. Next thing you know, you will have someone running ad-hoc queries that haven't been tuned, or, worse yet, you may have someone issuing ad-hoc INSERT, UPDATE, or DELETE commands. The product user profile allows you to defend against this risk. The Product_Profile Table The PRODUCT_PROFILE table is owned by SYSTEM and has the following structure: Name Null? Type PRODUCT NOT NULL VARCHAR2(30) USERID VARCHAR2(30) ATTRIBUTE VARCHAR2(240) SCOPE VARCHAR2(240) NUMERIC_VALUE NUMBER(15,2) CHAR_VALUE VARCHAR2(240) DATE_VALUE DATE LONG_VALUE LONG Most users will not have SELECT access on the table itself, so if you aren't logged in as SYSTEM, you may not be able to DESCRIBE the table. Instead, you should have access to a view on the table named PRODUCT_PRIVS. This view returns all the records from the PRODUCT_PROFILE table that apply to the currently loggedon useryou. Figure 91 shows the table, the view, the synonyms that normally exist, and the relationship between them. Table 9-1 describes the purpose of each of the element shown in Figure 9-1. How the Product User Profile Works when you log into an Oracle database using SQL*Plus, SQL*Plus will issue two SELECT statements against the product user profile. The first SELECT statement retrieves a list of command restrictions and looks like this: SELECT attribute, scope, numeric_value, char_value, date_value FROM system.product_privs WHERE (UPPER (SQL*Plus) LIKE UPPER (product)) AND (UPPER(user) LIKE UPPER(userid)) The two fields of interest to SQL*Plus are ATTRIBUTE and CHAR_VALUE. Together, these columns tell SQL*Plus which commands to disable for the cur- < previous page page_310 next page > < previous page page_311 next page > Page 311 Figure 9-1. The product user profile table, view, and synonyms Table 9-1. Product User Profile Elements Element Who Sees It? Purpose PRODUCT_PROFILE table SYSTEM This is the product user profile table itself. PRODUCT_USER_PROFILE SYSTEM Provides backwards compatibility, because the table name used to be PRODUCT_USER_PROFILE. PRODUCT_PRIVS view All users A view that shows each user the restrictions that apply to him or her. PRODUCT_USER_PROFILE public synonym All users A public synonym pointing to the view. PRODUCT_PROFILE public synonym All users A public synonym pointing to the view. < previous page page_311 next page > < previous page page_312 next page > Page 312 rently logged on user. For example, the following two rows will be returned for a user who has been denied access to the DELETE and HOST commands: ATTRIBUTE CHAR_VALUE DELETE DISABLED HOST DISABLED A second SELECT statement is issued against the product user profile in order to retrieve any role restrictions for the user. Here's what that statement looks like: SELECT char_value FROM system. product_privs WHERE (UPPER(SQL*Plus) LIKE UPPER (product)) AND ( (UPPER(user) LIKE UPPER(userid)) OR (UPPER(userid) = PUBLIC)) AND (UPPER (attribute) = ROLES) In this case, the CHAR_VALUE column returns a list of roles that are to be disabled whenever the user connects using SQL*Plus. SQL*Plus then disables these roles with a SET ROLE command. By way of example, assume that the following data was returned: CHAR_VALUE PAYROLL_ADMINISTRATOR HR_ADMINISTRATOR There are two roles to be disabled. SQL*Plus will turn them off by issuing the following command to Oracle: SET ROLE ALL EXCEPT payroll_administrator, hr_administrator This establishes the default condition for the user of having those roles turned off. The user may be able to issue another SET ROLE command to turn them back on again, but the starting condition is that the roles are off. If SQL*Plus's attempt to query the product user profile results in an error, perhaps because the table does not exist, you will see the following message from SQL*Plus: Error accessing PRODUCT_USER_PROFILE Warning: Product user profile information not loaded! You may need to run PUPBLD.SQL as SYSTEM Connected. If you do happen to get the above error message, see the section titled Creating the Profile Table later in this chapter, or notify your DBA. < previous page page_312 next page > < previous page page_313 next page > Page 313 The SYSTEM user presents a special case. If you log into Oracle as SYSTEM, SQL*Plus detects this, and does not query the product user profile. Therefore, you can never restrict what the SYSTEM user is allowed to do. Product User Profile Limitations The product user profile is used for application security. The application is SQL*Plus. No other applications respect the limitations set in the profile. In today's world, with ODBC (Open DataBase Connectivity) on every desktop, and every application under -the sun capable of connecting to an Oracle database, securing SQL*Plus should be only a small part of your overall security plan. It is relatively easy for someone with Microsoft Access, for example, to connect to an Oracle database. Once that's done, that user will be able to freely edit, insert, and delete any data to which they have access. Guard against this by implementing as much of your security at the database level as possible. There are also some potential security holes you should be aware of when using the product user profile to secure SQL*Plus. Oracle is a complex product, and often there is more than one way to accomplish any given task. You have to be particularly vigilant about the possible use of PL/SQL. The next two sections describe some known issues to be aware of when setting limits with the product user profile. Issues related to PL/SQL Any SQL command you can issue from the SQL*Plus prompt can also be issued from a PL/SQL block. Remember this. It's important. Using the profile, you can restrict a user's access to a SQL command, but it may be possible to get around that restriction with PL/SQL. For this reason, you may want to restrict access to PL/ SQL as well. Take the UPDATE command, for example. Using the profile, you can restrict a SQL*Plus user from issuing the UPDATE command. Should the user try an update, an error will be returned, as the following example shows: SQL> UPDATE sqlplus.employee invalid command: update This is all well and good, but the update can easily be coded in PL/SQL. Here's how: SQL> BEGIN 2 UPDATE sqlplus.employee < previous page page_313 next page > < previous page page_314 next page > Page 314 3 SET employee_billing_rate = 300 4 WHERE employee_id = 101; 5 END; 6 / PL/SQL procedure successfully completed. That was certainly easy enough, wasn't it? So much for your security. If you need to restrict a user from issuing any INSERT, UPDATE, DELETE, or SELECT commands, you should also restrict the user from using PL/SQL. Data definition language (DDL) commands, such as GRANT or CREATE TABLE, are a bit more difficult to code from PL/SQL, but they can be done. As long as a user has EXECUTE access to the DBMS_SQL package, you should consider the possibility that the user may be able to code dynamic SQL statements. Beginning with Oracle8i, a new version of dynamic SQL is being implemented. This will allow users to code dynamic SQL by simply embedding the desired commands in the PL/SQL block. Thus, the lack of EXECUTE privileges on the DBMS_SQL package won't necessarily stop the user from being able to issue dynamic SQL. There are two obvious ways to execute PL/SQL from SQL*Plus. One way is to type in a PL/SQL block at the command prompt and execute it. The other way is to use the SQL*Plus EXECUTE command. To restrict a user's access to PL/ SQL, you must disable the following three SQL*Plus commands: DECLARE BEGIN EXECUTE Leave any one of the above commands enabled, and you might as well leave them all enabled; the user will still have full access to PL/SQL. There are even less obvious ways to execute PL/SQL, and you may want to guard against these as well. The user could create a stored function and execute that from a SELECT statement, or the user could create a trigger on a table and then fire that trigger. The easiest way to guard against either of these possibilities is to ensure that the user does not have the system privileges required to do these things. An alternative would be to also restrict access to the CREATE command from SQL*Plus. Issues related to roles When you disable a role, SQL*Plus turns that role off when the user first connects, but that doesn't prevent the user from turning the role on again. The user can sim- < previous page page_314 next page > < previous page page_315 next page > Page 315 ply issue a SET ROLE command of his own, as the following example shows, turning the desired role back on: SQL> SELECT employee_name, employee_billing_rate 2 FROM sqlplus. employee; FROM Jeff.employee * ERROR at line 2: ORA-00942: table or view does not exist SQL> SET ROLE ALL; Role set. SQL>SELECT employee_name, employee_billing_rate 2 FROM jeff.employee; EMPLOYEE_NAME EMPLOYEE_BILLING_RATE Jonathan Gennick 300 Jenny Gennick 135 Jeff Gennick 99 In this example, the first SELECT failed because the PAYROLL_ADMINISTRATOR role had been disabled by SQL*Plus, and consequently the user could not see the EMPLOYEE table. Notice, though, that all the user had to do was issue a SET ROLE ALL command in order to enable the role, allowing him to see the data. It was not even necessary for the user to know the name of the specific role that needed to be enabled. For this reason, disabling the SET ROLE command should usually go hand in hand with disabling roles. If you've disabled a role for a user, and also disabled the SET ROLE command, you should give some thought to disabling PL/SQL as well. At the very least, you might want to revoke EXECUTE privileges on the DBMS_SQL package. The reason for this is that by using dynamic SQL, the SET ROLE command can be executed from within a PL/ SQL block. Admittedly, this would take a very knowledgeable and determined user, but it can be done. Here is an example: SQL> SELECT employee_name, employee_billing_rate 2 FROM sqlplus.employee; FROM sqlplus.employee * ERROR at line 2: ORA-00942: table or view does not exist SQL> SET ROLE ALL; invalid command: set role SQL> < previous page page_315 next page > < previous page page_316 next page > Page 316 SQL> DECLARE 2 set_role_cursor INTEGER; 3 rows_affected INTEGER; 4 BEGIN 5 set_role_cursor := DBMS_SQL_OPEN_CURSOR; 6 DBMS_SQL.PARSE (set_role_cursor, 7 SET ROLE payroll_administrator, 8 DBBS_SQL.NATIVE); 9 rows_affected := DBMS_SQL.EXECUTE(set_role_cursor); 10 DBMS_SQL.CLOSE_CURSOR (set_role_cursor); 11 END; 12 / PL/SQL procedure successfully completed. SQL> SELECT employee_name, employee_billing_rate 2 FROM sqlplus.employee; EMPLOYEE_NAME EMPLOYEE_BILLING_RATE Jonathan Gennick 300 Jenny Gennick 135 Jeff Gennick 99 SQL*Plus honors the restriction against using the SET ROLE command from the SQL*Plus prompt, but it has no way of knowing what is going on inside a PL/SQL block. Remember, PL/SQL is sent to the database for execution. SQL*Plus does not look inside a block. Using the Product User Profile To use the product user profile, the first thing you need to do is create it. Oracle provides a script for this purpose. Once the product user profile table has been created, there are three things you need to know how to do: Restrict a user, or group of users, from using a specific command. Set a role so that it will be disabled for a given user or group of users when SQL*Plus first connects. Report the restrictions currently in the profile table. The next few sections show you how to perform each of these tasks. Creating the Profile Table. Oracle supplies a script named PUPBLD.SQL that creates the table, views, and synonyms shown earlier in this chapter in Figure 9-1. On Windows-based systems, the < previous page page_316 next page > . issue dynamic SQL. There are two obvious ways to execute PL /SQL from SQL* Plus. One way is to type in a PL /SQL block at the command prompt and execute it. The other way is to use the SQL* Plus EXECUTE. and the likeOracle also provides an application security scheme for SQL* Plus. This allows you to control the specific commands a SQL* Plus user is allowed to execute. At the core of the SQL* Plus. Using the profile, you can restrict a SQL* Plus user from issuing the UPDATE command. Should the user try an update, an error will be returned, as the following example shows: SQL& gt; UPDATE sqlplus.employee