< previous page page_215 next page > Page 215 umns printing vertically, one after the other, instead of the more usual horizontal format. The result makes for a very readable display of the trigger definition. DESCRIPTION This script lists the definition of the specified trigger. USAGE @SHOW_TRIGGER [owner.] trigger_name SET ECHO OFF SET HEADING OFF SETRECSEP OFF SET NEWPAGE 1 SET VERIFY OFF SET FEEDBACK OFF SET PAGESIZE 0 SET LONG 10000 SET LINESIZE 80 Dissect the input argument, and get the owner name and table name into two separate substitution variables. The owner name defaults to the current user. DEFINE s_owner_name = DEFINE s_trigger_name = COLUMN owner_name NOPRINT NEW_VALUE s_owner_name COLUMN trigger_name NOPRINT NEW_VALUE s_trigger_name SELECT DECODE(INSTR(&&1 ,.), 0,USER, /*Default to current user.*/ UPPER(SUBSTR(&&1 ,1,INSTR(&&1, .)-1))) owner_name, DECODE (INSTR(&&1, .), 0,UPPER&&1), /*Only the table name was passed in.*/ UPPER(SUBSTR(&&1,INSTR(&&1, .)+1))) trigger_name FROM dual; Set up the formats COLUMN description FORMAT A60 WORD_WRAPPED COLUMN referencing_names FORMAT A60 WORD_WRAPPED FOLD_BEFORE COLUMN when_clause FORMAT A60 WORD_WRAPPED FOLD_BEFORE COLUMN trigger_body FORMAT A80 WRAPPED FOLD_BEFORE SELECT TRIGGER ¦¦ &&s__owner_name ¦¦ RTRIM (description) description, RTRIM(referencing_names) referencing_names, WHEN ¦¦ when_clause when_clause, trigger_body FROM all_triggers WHERE owner = &&s_owner_name AND trigger_name = &&s_trigger_name; Reset everything back to its default setting TTITLE OFF SET HEADING ON SET RECSEP WRAPPED < previous page page_215 next page > < previous page page_216 next page > Page 216 SET VERIFY ON SET FEEDBACK ON SET PAGESIZE 24 SET LONG 80 CLEAR BREAKS CLEAR COLUMNS Running the SHOW_TRIGGER.SQL script Here are the results of executing the SHOW_TRIGGER script to see the definition of a trigger named TEST_1: SQL> @show_trigger emp)_hire_date_check TRIGGER JEFF.emp_hire_date_check BEFORE INSERT OR UPDATE ON employee FOR EACH ROW REFERENCING NEW AS NEW OLD AS OLD WHEN BEGIN IF :NEW.employee_hire_date < TRUNC(SYSDATE - 30) THEN RAISE_APPLICATION_ERROR (-20000, An employees hire date may only be backdated 30 days, and not more.); END IF; END; The LIST_TRIGGERS.SQL script Instead of looking at one specific trigger, you may want to look at all the triggers that are defined on a specific table. It turns out that you can readily do this with only two slight modifications to the SHOW_TRIGGER script. One is to interpret the first argument as a table name, not a trigger name. The other is to use the table name in the WHERE clause of the SELECT statement. The following script will list all the triggers defined on a table: DESCRIPTION This script lists the definition of the specified trigger. USAGE @LIST_TRIGGERS [owner.]table_name SET ECHO OFF SET HEADING OFF SET RECSEP OFF SET NEWPAGE 1 SET VERIFY OFF SET FEEDBACK OFF SET PAGESIZE 0 SET LONG 10000 SET LINESIZE 80 Dissect the input argument, and get the owner name and table name into two separate substitution variables. < previous page page_216 next page > < previous page page_217 next page > Page 217 The owner name defaults to the current user. DEFINE s_owner_name = DEFINE s_table_name = COLUMN owner_name NOPRINT NEW_VALUE s_owner_name COLUMN table_name NOPRINT NEW_VALUE s_table_name SELECT DECODE (INSTR( &&1,.), 0,USER, /*Default to current user.*/ UPPER(SUBSTR(&&1,1,INSTR(&&1,.)-1))) owner_name, DECODE (INSTR(&&1,.), 0,UPPER(&&1), /*Only the table name was passed in.*/ UPPER(SUBSTR(&&1,INSTR(&&1,.)+1))) table_name FROM dual; Set up the formats COLUMN description FORMAT A60 WORD_WRAPPED COLUMN referencing_names FORMAT A60 WORD_WRAPPED FOLD_BEFORE COLUMN when_clause FORMAT A60 WORD_WRAPPED FOLD_BEFORE COLUMN trigger_body FORMAT A80 WRAPPED FOLD_BEFORE SELECT TRIGGER ¦¦ &&s_owner_name ¦¦ RTRIM (description) description, RTRIM(referencing_names) referencing_names, WHEN ¦¦ when_clause when_clause, trigger_body FROM all_triggers WHERE owner = &&s_owner_name AND table_name = &&s_table_name; Reset everything back to its default setting TTITLE OFF SET HEADING ON SET RECSEP WRAPPED SET VERIFY ON SET FEEDBACK ON SET PAGESIZE 24 SET LONG 80 CLEAR BREAKS CLEAR COLUMNS Running the LIST_TRIGGERS script The following are the results of running the LIST_TRIGGERS script on a table that happens to have two triggers defined. SQL> @list_triggers employee TRIGGER JEFF.emp_delete_check BEFORE DELETE ON employee FOR EACH ROW REFERENCING NEW AS NEW OLD AS OLD WHEN BEGIN IF (:OLD.employee_termination_date IS NULL) < previous page page_217 next page > < previous page page_218 next page > Page 218 OR (:OLD.employee_termination_date >= TRUNC(SYSDATE)+1 THEN RAISE_APPLICATION_ERROR (-20001, You must terminate an employee before deleting his record.); END IF; END; TRIGGER JEFF.emp_hire_date_check BEFORE INSERT OR UPDATE ON employee FOR EACH ROW REFERENCING NEW AS NEW OLD AS OLD WHEN BEGIN IF :NEW.employee_hire_date < TRUNC(SYSDATE - 30) THEN RAISE_APPLICATION_ERROR (-20000,An employee s hire date may only be backdated 30 days, and not more.); END IF; END; Synonyms A synonym is an alternate name for a table. By coding your programs to use synonyms instead of table names, you insulate yourself from any changes in the name, ownership, or location of those tables. All of the scripts in this chapter have actually used synonyms instead of table names. ALL_TABLES, for example, is actually a public synonym for the SYS.ALL_TABLES table. Looking at Synonyms To look at a synonym, you just select information from ALL_SYNONYMS for the synonym you are interested in. The following SELECT is an example: SELECT * FROM all_synonyms WHERE synonym_owner = username AND synonym_name = synonym_name So far, so good. However, there are two types of synonyms: public and private. Synonyms owned by a user are private synonyms and affect only that user. Public synonyms are owned by PUBLIC and affect all database users. If you are interested in a specific synonym, you probably also want to know if both public and private versions exist. Because of that, you might modify your query to look like this: SELECT * FROM all_synonyms WHERE synonym_owner = username AND synonym_name = synonym_name UNION SELECT * < previous page page_218 next page > < previous page page_219 next page > Page 219 FROM all_synonyms WHERE synonym_owner = PUBLIC AND synonym_name = synonym_name Now you will see both synonym types, which is helpful in detecting cases where a private synonym conflicts with a public synonym. Private synonyms override public synonym definitions, so it's important to know when both types exist. Synonym Scripts The following sections describe scripts that will let you list synonym definitions. The SHOW_SYN.SQL script The following SQL*Plus script lists the definition of the synonym that you specify as an argument. If a matching public synonym exists, it will be listed as well. The results are sorted by owner and synonym name, and the owner column is decoded in such a way as to make PUBLIC sort first. DESCRIPTION This script displays the definition of a synonym. USAGE @SHOW_SYN [owner.] synonym_name SET ECHO OFF SET VERIFY OFF SET FEEDBACK OFF Dissect the input argument, and get the owner name and synonym name into two separate substitution variables. The owner name defaults to the current user. SET TERMOUT OFF DEFINE s_owner_name = DEFINE s_synonym_name = COLUMN owner_name NOPRINT NEW_VALUE s_owner_name COLUMN synonym_name NOPRINT NEW_VALUE s_synonym_name SELECT DECODE(INSTR(&&1,.), 0,USER, /*Default to current user.*/ UPPER(SUBSTR(&&1,1,INSTR(&&1, .)-1))) owner_name, DECODE (INSTR(&&1,.), 0,UPPER(&&1), /*Only the table name was passed in.*/ UPPER(SUBSTR(&&, INSTR(&&1,.)+1))) synonym_name FROM dual; CLEAR COLUMNS SET TERMOUT ON Display information about the synonym Information is displayed in three lines to accommodate the longest possible values for each data element. The matching public synonym, if one exists, is < previous page page_219 next page > < previous page page_220 next page > Page 220 always shown as well. SET HEADING OFF SET NEWPAGE NONE SET PAGESIZE 0 SET RECSEP OFF SET LINESIZE 80 COLUMN owner NOPRINT COLUMN synonym_name NOPRINT COLUMN syn_def FORMAT A80 word_wrapped PROMPT SELECT DECODE(owner,PUBLIC,1 ¦¦ owner,2 ¦¦ owner) owner, synonym_name, owner ¦¦ . ¦¦ synonym_name ¦¦ synonym for ¦¦ table_owner ¦¦ . ¦¦ table_name ¦¦ DECODE(db_link,NULL,NULL,CHR(10) ¦¦ at ¦¦ db_link) syn_def FROM all_synonyms WHERE owner = &&s_owner_name AND synonym_name = &&s_synonym_name UNION SELECT DECODE(owner,PUBLIC,1 ¦¦ owner,2 ¦¦ owner) owner, synonym_name, synony_name ¦ ¦ PUBLIC synonym for ¦¦ table_owner ¦¦ . ¦ ¦ table_name ¦ ¦DECODE (db_link,NULL, NULL, CHR(10) ¦¦ at ¦¦ db_link) syn_def FROM all_synonyms WHERE owner = PUBLIC AND synonym_name = &&s_synonym_name ORDER BY owner,synonym_name; Reset everything back to its default. CLEAR COLUMNS UNDEFINE s_owner_name UNDEFINE s_synonym_name SET HEADING ON SET NEWPAGE 1 SET PAGESIZE 14 SET VERIFY ON SET RECSEP WRAPPED SET FEEDBACK ON :Running the SHOW_SYN.SQL script Here are the results of executing the SHOW_SYN script to describe the ALL_TABLES synonym: SQL> @show_syn all_tables ALL_TABLES PUBLIC synonym for SYS.ALL_TABLES JEFF.ALL_TABLES synonym for SYS.ALL_TABLES As you can see, ALL_TABLES is a public synonym pointing to SYS.ALL_TABLES. In this case, the current user has a private synonym of the same name. This private synonym also points to SYS.ALL_TABLES. < previous page page_220 next page > < previous page page_221 next page > Page 221 The LIST_SYN script In addition to seeing the definition for one synonym, you may also want to see all synonyms owned by a particular user. The following script will let you do that: DESCRIPTION List synonyms owned by the current user, or owned by a specified user. The user is prompted for an owner name. If an owner is not specified, i.e., the user just presses ENTER, then synonyms are listed for the current user. SET ECHO OFF SET FEEDBACK OFF SET VERIFY OFF SET DEFINE ON SET HEADING OFF Ask the user for the owner. ACCEPT username CHAR PROMPT List synonyms for user: PROMPT Set up the title to print the owner. TTITLE LEFT SYNONYMS OWNED BY: owner SKIP 1 COLUMN owner NOPRINT NEW_VALUE owner List synonyms owned by the user specified Information is displayed in three lines to accommodate the longest possible values for each data element. COLUMN owner NOPRINT COLUMN synonym_name NOPRINT COLUMN db_link FORMAT A60 WRAPPED PROMPT SELECT owner, synonym_name, ¦¦ owner ¦¦ . ¦¦ synonym_name ¦¦ synonym for ¦¦ table_owner ¦¦ . ¦¦ table_name ¦¦ DECODE(db_link,NULL,NULL,CHR(10) ¦¦ at ¦¦ db_link) syn_def FROM all_syonynms WHERE owner = DECODE(&&usenrname,NULL,USER,UPPER(&&username)) ORDER BY synonym_name; Clean up: undefine vars, clear columns, change settings back to defaults. UNDEFINE username UNDEFINE owner COLUMN owner CLEAR TTITLE OFF SET HEADING ON SET FEEDBACK ON SET VERIFY ON One thing you should be aware of when looking at synonyms is that unless you are the database administrator, you won't really be able to look at all synonyms < previous page page_221 next page > < previous page page_222 next page > Page 222 owned by other users. The ALL_SYNONYMS view shows you three types of synonyms: Public synonyms (owned by PUBLIC) Synonyms you own Synonyms owned by other users that reference tables and other objects to which you have access The only time the ALL_SYNONYMS view would show you all the synonyms in the database would be if you happened to have access to all the objects in the database. Running the LIST_SYN.SQL script Here is a sample execution of the LIST_SYN script that shows all the public synonyms: SQL> @list_syn List tables for user: public SYNONYMS OWNED BY: PUBLIC PUBLIC.ALL_ALL_TABLES synonym for SYS.ALL_ALL_TABLES PUBLIC.ALL_ARGUMENTS synonym for SYS.ALL_ARGUMENTS PUBLIC.ALL_CATALOG synonym for SYS.ALL_CATALOGP PUBLIC.ALL_CLUSTERS synonym for SYS.ALL_CLUSTERS The next example shows LIST_SYN being used to list all synonyms owned by the current user: SQL> @list_syn List synonyms for user: SYNONYMS OWNED BY: JEFF JEFF.ALL_CONSTRAINTS synonym for SYS.ALL_CONSTRAINTS JEFF.ALL_INDEXES synonym for SYS.ALL_INDEXES JEFF.ALL_TABLES synonym for SYS.ALL_TABLES You could also use LIST_SYN to see a list of synonyms owned by some other users that reference objects to which you have access. Just run the script, and enter the username of interest. Table Security Information about who has been granted access to a particular table can be found in two views, the ALL_TAB_PRIVS view and the ALL_COL_PRIVS view. These views show you information about privileges granted on tables you own or privileges you have been granted on tables owned by other users. Unless you are the < previous page page_222 next page > < previous page page_223 next page > Page 223 DBA or otherwise have access to the DBA_TAB_PRIVS_MADE and DBA_COL_PRIVS_MADE views, you cannot fully see the security for tables you do not own. Looking at Table Security As stated earlier, there are two views you need to look at when you want to find out who has access to a particular table. The ALL_TAB_PRIVS view gives you information about table-level grants. For example, if you issue the following statement, it will be reflected in ALL_TAB_PRIVS: GRANT SELECT, DELETE ON employee TO user_a; Some privileges, UPDATE and INSERT, for example, may be restricted only to certain columns of a table. For example, the following grant allows user_a to change just the employee's name: GRANT UPDATE (employee_name) ON employee TO user_a; Grants such as this, which are restricted to certain columns, are reflected in the ALL_COL_PRIVS view. To get a complete picture of the privileges you have granted on any particular table, you need to query both of these views. The query against ALL_TAB_PRIVS will look something like this: SELECT grantee, privilege, grantable FROM all_tab_privs WHERE table_schema = owner_name AND table_name = object_name; This query will give you a list of all privileges that have been granted without any column restrictions. The GRANTABLE column will tell you whether or not the privilege was granted using the WITH GRANT OPTION keywords. Granting a privilege with GRANT OPTION allows the grantee to pass that privilege on to others. You also need to know about any column-level privileges that have been granted. These will only be reflected in ALL_COL_PRIVS, so you must query that as well. This query looks similar to the previous query, except that it also returns the column names: SELECT grantee, privilege, column_name, grantable FROM all_col_privs WHERE table_schema = owner_name AND table_name = object_name; Security Scripts. The SHOW_SECURITY script you are about to see unions together the two queries we saw in the previous section. < previous page page_223 next page > . name. The other is to use the table name in the WHERE clause of the SELECT statement. The following script will list all the triggers defined on a table: DESCRIPTION This script lists the definition. exist. Synonym Scripts The following sections describe scripts that will let you list synonym definitions. The SHOW_SYN .SQL script The following SQL* Plus script lists the definition of the synonym that. access The only time the ALL_SYNONYMS view would show you all the synonyms in the database would be if you happened to have access to all the objects in the database. Running the LIST_SYN .SQL script Here