Professional Documents
Culture Documents
What Is SQL and Where Does It Come From?: Back To Top of File
What Is SQL and Where Does It Come From?: Back To Top of File
Delete from emp x where rowid <= ( select max(rowid) from emp y where
x.rowid = y.rowid)
Select * from (select * from emp order by sal desc) where rownum < 6
Show all data for Clerks hired after the year 1997
3) Show the employees who have no commission not have a 10% raise in
salary (round off salaries)
Select ‘the salary of’|| last_name||’after a 10% raise is’ from employees
Where commission_pct is null;
In common usage SQL also encompasses DML (Data Manipulation Language), for
INSERTs, UPDATEs, DELETEs and DDL (Data Definition Language), used for creating
and modifying tables and other database structures.
The development of SQL is governed by standards. A major revision to the SQL standard
was completed in 1992, called SQL2. SQL3 support object extensions and are (partially?)
implemented in Oracle8 and 9.
How does one escape special characters when building SQL queries?
The LIKE keyword allows for string searches. The '_' wild card character is used to
match exactly one character, '%' is used to match zero or more occurrences of any
characters. These characters can be escaped in SQL. Example:
SELECT name FROM emp WHERE id LIKE '%\_%' ESCAPE '\';
Choose one of the following queries to identify or remove duplicate rows from a table
leaving only unique records in the table:
Method 1:
Note 2: If you are comparing NOT-NULL columns, use the NVL function. Remember
that NULL is not equal to NULL. This should not be a problem as all key columns should
be NOT NULL by definition.
Create your table with a NOT NULL column (say SEQNO). This column can now be
populated with unique values:
SQL> UPDATE table_name SET seqno = ROWNUM;
If you don't want to go through the floor and ceiling math, try this method (contributed by
Erik Wile):
select to_char(to_date('00:00:00','HH24:MI:SS') +
(date1 - date2), 'HH24:MI:SS') time_difference
from ...
Note that this query only uses the time portion of the date and ignores the date itself. It
will thus never return a value bigger than 23:59:59.
The SYSDATE pseudo-column shows the current system date and time. Adding 1 to
SYSDATE will advance the date by 1 day. Use fractions to add hours, minutes or
seconds to the date. Look at these examples:
SQL> select sysdate, sysdate+1/24, sysdate +1/1440, sysdate +
1/86400 from dual;
NOW NOW_PLUS_30_SECS
-------------------- --------------------
03-JUL-2002 16:47:23 03-JUL-2002 16:47:53
Here are a couple of examples:
Description Date Expression
Now SYSDATE
Tomorow/ next day SYSDATE + 1
Seven days from now SYSDATE + 7
One hour from now SYSDATE + 1/24
Three hours from now SYSDATE + 3/24
An half hour from now SYSDATE + 1/48
10 minutes from now SYSDATE + 10/1440
30 seconds from now SYSDATE + 30/86400
Tomorrow at 12 midnight TRUNC(SYSDATE + 1)
Tomorrow at 8 AM TRUNC(SYSDATE + 1) + 8/24
Next Monday at 12:00 noon NEXT_DAY(TRUNC(SYSDATE), 'MONDAY') + 12/24
First day of next month at 12
TRUNC(LAST_DAY(SYSDATE ) + 1)
midnight
First day of the current month TRUNC(LAST_DAY(ADD_MONTHS(SYSDATE,-1))) + 1
The next Monday, Wednesday TRUNC(LEAST(NEXT_DAY(sysdate,''MONDAY'' ),NEXT_DAY(sysdate,''WEDNESDAY''),
or Friday at 9 a.m NEXT_DAY(sysdate,''FRIDAY'' ))) + (9/24)
Use this simple query to count the number of data values in a column:
select my_table_column, count(*)
from my_table
group by my_table_column;
Rupak Mohan provided this solution to select the Nth row from a table:
SELECT * FROM t1 a
WHERE n = (SELECT COUNT(rowid)
FROM t1 b
WHERE a.rowid >= b.rowid);
SELECT * FROM (
SELECT ENAME,ROWNUM RN FROM EMP WHERE ROWNUM < 101 )
WHERE RN = 100;
Note: In this first query we select one more than the required row number, then we select
the required one. Its far better than using a MINUS operation.
SELECT f1 FROM t1
WHERE rowid = (
SELECT rowid FROM t1
WHERE rownum <= 10
MINUS
SELECT rowid FROM t1
WHERE rownum < 10);
SELECT rownum,empno FROM scott.emp a
GROUP BY rownum,empno HAVING rownum = 4;
Alternatively...
SELECT * FROM emp WHERE rownum=1 AND rowid NOT IN
(SELECT rowid FROM emp WHERE rownum < 10);
Please note, there is no explicit row order in a relational database. However, this query is
quite fun and may even help in the odd situation.
Back to top of file
Can one retrieve only rows X to Y from a table?
Another solution is to use the MINUS operation. For example, to display rows 5 to 7,
construct a query like this:
SELECT *
FROM tableX
WHERE rowid in (
SELECT rowid FROM tableX
WHERE rownum <= 7
MINUS
SELECT rowid FROM tableX
WHERE rownum < 5);
Youssef Youssef provided this soluton: "this one was faster for me and allowed for
sorting before filtering by rownum. The inner query (table A) can be a series of tables
joined together with any operation before the filtering by rownum is applied."
SELECT *
FROM (SELECT a.*, rownum RN
FROM (SELECT *
FROM t1 ORDER BY key_column) a
WHERE rownum <=7)
WHERE rn >=5
Please note, there is no explicit row order in a relational database. However, this query is
quite fun and may even help in the odd situation.
Back to top of file
One can easily select all even, odd, or Nth rows from a table using SQL queries like this:
SELECT *
FROM emp
WHERE (ROWID,0) IN (SELECT ROWID, MOD(ROWNUM,4)
FROM emp);
Method 2: Use dynamic views (available from Oracle7.2):
SELECT *
FROM ( SELECT rownum rn, empno, ename
FROM emp
) temp
WHERE MOD(temp.ROWNUM,4) = 0;
Method 3: Using GROUP BY and HAVING - provided by Ravi Pachalla
SELECT rownum, f1
FROM t1
GROUP BY rownum, f1 HAVING MOD(rownum,n) = 0 OR rownum = 2-n
Please note, there is no explicit row order in a relational database. However, these queries
are quite fun and may even help in the odd situation.
Back to top of file
Form Oracle8i one can have an inner-query with an ORDER BY clause. Look at this
example:
SELECT *
FROM (SELECT * FROM my_table ORDER BY col_name_1 DESC)
WHERE ROWNUM < 10;
Use this workaround with prior releases:
SELECT *
FROM my_table a
WHERE 10 >= (SELECT COUNT(DISTINCT maxcol)
FROM my_table b
WHERE b.maxcol >= a.maxcol)
ORDER BY maxcol DESC;
Back to top of file
Tree-structured queries are definitely non-relational (enough to kill Codd and make him
roll in his grave). Also, this feature is not often found in other database offerings.
The LEVEL pseudo-column is an indication of how deep in the tree one is. Oracle can
handle queries with a depth of up to 255 levels. Look at this example:
One way of working around this is to use PL/SQL, open the driving cursor with the
"connect by prior" statement, and the select matching records from other tables on a row-
by-row basis, inserting the results into a temporary table for later retrieval.
The Oracle decode function acts like a procedural statement inside an SQL statement to
return different values or columns based on the values of other columns in the select
statement.
Some examples:
select decode(sex, 'M', 'Male', 'F', 'Female', 'Unknown')
from employees;
From Oracle 8i one can also use CASE statements in SQL. Look at this example:
SELECT ename, CASE WHEN sal>1000 THEN 'Over paid' ELSE 'Under
paid' END
FROM emp;
Back to top of file
How can one dump/ examine the exact content of a database column?
SELECT DUMP(col1)
FROM tab1
WHERE cond1 = val1;
DUMP(COL1)
-------------------------------------
Typ=96 Len=4: 65,66,67,32
For this example the type is 96, indicating CHAR, and the last byte in the column is 32,
which is the ASCII code for a space. This tells us that this column is blank-padded.
Back to top of file
From Oracle8i one can DROP a column from a table. Look at this sample script,
demonstrating the ALTER TABLE table_name DROP COLUMN column_name;
command.
Other workarounds:
1. SQL> update t1 set column_to_drop = NULL;
SQL> rename t1 to t1_base;
SQL> create view t1 as select <specific columns> from t1_base;
From Oracle9i one can RENAME a column from a table. Look at this example:
ALTER TABLE tablename RENAME COLUMN oldcolumn TO newcolumn;
Other workarounds:
From Oracle8 you can just type "password" from SQL*Plus, or if you need to change
another user's password, type "password user_name".
Perform an "ALTER SEQUENCE ... NOCACHE" to unload the unused cached sequence
numbers from the Oracle library cache. This way, no cached numbers will be lost. If you
then select from the USER_SEQUENCES dictionary view, you will see the correct high
water mark value that would be returned for the next NEXTVALL call. Afterwards,
perform an "ALTER SEQUENCE ... CACHE" to restore caching.
You can use the above technique to prevent sequence number loss before a SHUTDOWN
ABORT, or any other operation that would cause gaps in sequence values.
You can use the SQL*Plus COPY command instead of snapshots if you need to copy
LONG and LONG RAW variables from one location to another. Eg:
COPY TO SCOTT/TIGER@REMOTE -
CREATE IMAGE_TABLE USING -
SELECT IMAGE_NO, IMAGE -
FROM IMAGES;
Note: If you run Oracle8, convert your LONGs to LOBs, as it can be replicated.
Back to top of file
o
o Sample SQL matrix report
SELECT job,
sum(decode(deptno,10,sal)) DEPT10,
sum(decode(deptno,20,sal)) DEPT20,
sum(decode(deptno,30,sal)) DEPT30,
sum(decode(deptno,40,sal)) DEPT40
FROM scott.emp
GROUP BY job
/
-- Sample output:
--
-- JOB DEPT10 DEPT20 DEPT30 DEPT40
-- --------- ---------- ---------- ---------- ----------
-- ANALYST 6000
-- CLERK 1300 1900 950
-- MANAGER 2450 2975 2850
-- PRESIDENT 5000
-- SALESMAN 5600
--
o
o Lookup Oracle error messages
set serveroutput on
set veri off feed off
select banner
from sys.v_$version;
begin
dbms_output.put_line('Port String: '||dbms_utility.port_string);
end;
/
@store
set termout on
o
o Select the Nth highest value from a table
-- Example :
--
-- Given a table called emp with the following columns:
-- id number
-- name varchar2(20)
-- sal number
--
-- For the second highest salary:
--
select level, max(sal) from emp
where level=2
connect by prior sal > sal
group by level
--
o
o Select the Nth lowest value from a table
-- Example:
--
-- Given a table called emp with the following columns:
-- id number
-- name varchar2(20)
-- sal number
--
-- For the second lowest salary:
--
-- select level, min(sal) from emp
-- where level=2
-- connect by prior sal < sal
-- group by level
--
o
o Demonstrate default column values
drop table x
-- /
select * from x
/
--
-- Expected output:
--
-- A B C D
-- - ---------- ----------- ------
-- a 99999 25-APR-2001 qwerty
-
o
o Display table and column comments
The following code tells the database what the application is up to:
begin
dbms_application_info.set_client_info('BANCS application info');
dbms_application_info.set_module('BANCS XYZ module', 'BANCS action
name');
end;
/
select sql_text
from sys.v_$sqlarea
where module = 'BANCS XYZ module'
and action = 'BANCS action name'
/
o
o SQL*Plus Help script
select info
from system.help
where upper(topic)=upper('&1')
o
o Test for Leap Years
select year,
decode( mod(year, 4), 0,
decode( mod(year, 400), 0, 'Leap Year',
decode( mod(year, 100), 0, 'Not a Leap Year', 'Leap Year')
), 'Not a Leap Year'
) as leap_year_indicator
from my_table
SELECT TRANSLATE(
'HELLO WORLD', -- Message to encode
'ABCDEFGHIJKLMNOPQRSTUVWXYZ ',
'1234567890!@#$%^&*()-=_+;,.') ENCODED_MESSAGE
FROM DUAL
/
SELECT TRANSLATE(
'85@@%._%*@4', -- Message to decode
'1234567890!@#$%^&*()-=_+;,.',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ ') DECODED_MESSAGE
FROM DUAL
o
o Count the number of rows for ALL tables in current schema
set termout off echo off feed off trimspool on head off pages 0
spool countall.tmp
select 'SELECT count(*), '''||table_name||''' from '||table_name||';'
from user_tables
/
spool off
set termout on
@@countall.tmp
set head on feed on
o
o Demonstrate Oracle database types and object tables
-- Clean-up...
DROP TABLE varray_table;
o DROP TYPE vcarray
o Demonstrate Oracle temporary tables
drop table x
/
select * from x;
commit;
-- Note: the same procdure can be used to convert LONG RAW datatypes to
BLOBs.
o
o Delete duplicate values from a table
-- Example :
--
-- Given a table called emp with the following columns:
-- id number
-- name varchar2(20)
-- sal number
--
-- To delete the duplicate values:
--
-- DELETE FROM emp
-- WHERE ROWID NOT IN (SELECT MIN(ROWID) FROM emp GROUP BY id);
--
-- COMMIT;
--
o
loop
update tab1 set col1 = 'value2'
where rowid = c1.rowid;
end loop;
commit;
end;
/
-- Note: More advanced users can use the mod() function to commit every
N rows.
-- No counter variable required:
--
-- if mod(i, 10000)
-- commit;
-- dbms_output.put_line('Commit issued for rows up to: '||
c1%rowcount);
-- end if;
--
o
o Simple program to demonstrate BULK COLLECT and BULK BIND operations
DECLARE
CURSOR emp_cur IS SELECT * FROM EMP;
END LOOP;
CLOSE emp_cur;
END;
/
o
o Profile PL/SQL code for execution statistics
conn / as sysdba
set serveroutput on
declare
-- Declare the PL/SQL table
type deptarr is table of dept%rowtype
index by binary_integer;
d_arr deptarr;
-- Declare cursor
type d_cur is ref cursor return dept%rowtype;
c1 d_cur;
i number := 1;
begin
-- Populate the PL/SQL table from the cursor
open c1 for select * from dept;
loop
exit when c1%NOTFOUND;
fetch c1 into d_arr(i);
i := i+1;
end loop;
close c1;
DBMS_OBFUSCATION_TOOLKIT.DESENCRYPT(
input_string => v_data,
key_string => c_encrypt_key,
encrypted_string => v_encrypted_val);
return v_encrypted_val;
end encrypt;
end PASSWORD;
/
show errors
-- Test if it is working...
select password.encrypt('PASSWORD1') from dual;
select password.decrypt(app_password.encrypt('PASSWORD1')) from dual;
select password.encrypt('PSW2') from dual;
select password.decrypt(app_password.encrypt('PSW2')) from dual;
o
o Pass result sets (REF CURSOR) between procedures and functions
set serveroutput on
END;
/
show errors
EXEC test_ref_cursor.main;
o
o Convert between different numbering systems (binary, octal, decimal and hex)
set serveroutput on
END dbms_numsystem;
/
show errors
-- Examples:
select dbms_numsystem.dec2bin(22) from dual;
select dbms_numsystem.bin2dec('10110') from dual;
select dbms_numsystem.dec2oct(44978) from dual;
select dbms_numsystem.oct2dec(127662) from dual;
select dbms_numsystem.dec2hex(44978) from dual;
select dbms_numsystem.hex2dec('AFB2') from dual;
o
o Random number/ string generator package
begin
select userenv('SESSIONID')
into Seed
from dual;
end random;
/
-- Some examples:
select random.rand_max(10) from dual;
select random.rand_max(10) from dual;
select random.rand_string(20) from dual;
select random.rand_string(20) from dual;
o
o Function to test for Leap Years
-- Let's test it
SET SERVEROUTPUT ON
BEGIN
IF isLeapYear(2004) THEN
dbms_output.put_line('Yes, it is a leap year');
ELSE
dbms_output.put_line('No, it is not a leap year');
END IF;
END;
/
o
o Print the ASCII table
declare
i number;
j number;
k number;
begin
for i in 2..15 loop
for j in 1..16 loop
k:=i*16+j;
dbms_output.put((to_char(k,'000'))||':'||chr(k)||' ');
if k mod 8 = 0 then
dbms_output.put_line('');
end if;
end loop;
end loop;
end;
/
show errors
o
o Recursive algorithms to calculate Fibonacci and Factorials
-- Test n!
SELECT fac(1), fac(2), fac(3), fac(4), fac(5) FROM dual;
-- Sample output:
-- FAC(1) FAC(2) FAC(3) FAC(4) FAC(5)
-- ---------- ---------- ---------- ---------- ----------
-- 1 2 6 24 120
-- Sample output:
-- FIB(1) FIB(2) FIB(3) FIB(4) FIB(5)
-- ---------- ---------- ---------- ---------- ----------
-- 1 1 2 3 5
--
o
o Fetch LOB column values piece-wise from PL/SQL
set serveroutput on
DECLARE
clob_locator CLOB;
charbuf VARCHAR2(20);
read_offset INTEGER;
read_amount INTEGER;
BEGIN
-- First we need to get the lob locator
SELECT c_lob INTO clob_locator FROM lob_table WHERE id = 1;
set serveroutput on
DROP TABLE lob_table;
DROP SEQUENCE lob_seq;
DBMS_LOB.OPEN(src_lob, DBMS_LOB.LOB_READONLY);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_lob,
SRC_LOB => src_lob,
AMOUNT => DBMS_LOB.GETLENGTH(src_lob) );
DBMS_LOB.CLOSE(src_lob);
COMMIT;
END;
/
show errors
-- Let's test it
exec load_file('pic1.gif');
SELECT id, DBMS_LOB.GETLENGTH(fil) AS bytes_loaded
FROM lob_table;
rem
-----------------------------------------------------------------------
rem Filename: savelob.sql
rem Purpose: Save a binary file (images, documents, etc) from
database
rem to a flat file.
rem Author: Frank Naude, Oracle FAQ
rem
-----------------------------------------------------------------------
DBMS_LOB.OPEN(v_lob_loc, DBMS_LOB.LOB_READONLY);
v_out_file := UTL_FILE.FOPEN(location => 'MY_DIR',
filename => p_file,
open_mode => 'w',
max_linesize => 32767);
UTL_FILE.FCLOSE(v_out_file);
DBMS_LOB.CLOSE(v_lob_loc);
END;
/
show errors
-- Let's test it
exec save_file(1, 'pic2.gif');
! ls -l /app/oracle/pic*.gif
set serveroutput on
DECLARE
cur1 PLS_INTEGER := DBMS_SQL.OPEN_CURSOR;;
rc NUMBER;
long_piece VARCHAR2(256);
piece_len INTEGER := 0;
long_tab DBMS_SQL.VARCHAR2S;
long_len INTEGER := 0;
BEGIN
DBMS_SQL.PARSE(cur1, 'select longcol from longtable',
DBMS_SQL.NATIVE);
DBMS_SQL.DEFINE_COLUMN_LONG(cur1, 1);
rc := DBMS_SQL.EXECUTE(cur1);
rc := DBMS_SQL.FETCH_ROWS(cur1); -- Get one row
-- Loop until all pieces of the long column are processed
LOOP
DBMS_SQL.COLUMN_VALUE_LONG(cur1, 1, 256, long_len, long_piece,
piece_len);
EXIT WHEN piece_len = 0;
DBMS_OUTPUT.PUT_LINE('Long piece len='|| piece_len);
DECLARE
fileHandler UTL_FILE.FILE_TYPE;
BEGIN
fileHandler := UTL_FILE.FOPEN('test_dir', 'test_file.txt', 'W');
UTL_FILE.PUTF(fileHandler, 'Look ma, I''m writing to a file!!!\n');
UTL_FILE.FCLOSE(fileHandler);
EXCEPTION
WHEN utl_file.invalid_path THEN
raise_application_error(-20000, 'ERROR: Invalid path for file.');
END;
o
o Map an external file to a database view
-- Test it!!!
set pages 50000
select * from alert_log_file
where text like '%ORA-%'
/
o
o Demonstrate Dynamic SQL
SET SERVEROUTPUT ON
conn / as sysdba
-- @?/javavm/install/initjvm.sql
grant javauserpriv to scott;
conn scott/tiger
o
o Execute Operating System commands from PL/SQL (Java call)
rem
-----------------------------------------------------------------------
rem Filename: oscmd.sql
rem Purpose: Execute operating system commands from PL/SQL
rem Notes: Specify full paths to commands, for example,
rem specify /usr/bin/ps instead of ps.
rem Date: 09-Apr-2005
rem Author: Frank Naude, Oracle FAQ
rem
-----------------------------------------------------------------------
rem
-----------------------------------------------------------------------
rem Grant Java Access to user SCOTT
rem
-----------------------------------------------------------------------
conn / as sysdba
EXEC dbms_java.grant_permission('SCOTT',
'SYS:java.lang.RuntimePermission', 'writeFileDescriptor', '');
EXEC dbms_java.grant_permission('SCOTT',
'SYS:java.lang.RuntimePermission', 'readFileDescriptor', '');
EXEC dbms_java.grant_permission('SCOTT', 'SYS:java.io.FilePermission',
'/bin/sh', 'execute');
-- Other read ,write or execute permission may be requried
rem
-----------------------------------------------------------------------
rem Create Java class to execute OS commands...
rem
-----------------------------------------------------------------------
conn scott/tiger
};
/
show errors
rem
-----------------------------------------------------------------------
rem Publish the Java call to PL/SQL...
rem
-----------------------------------------------------------------------
rem
-----------------------------------------------------------------------
rem Let's test it...
rem
-----------------------------------------------------------------------
CALL DBMS_JAVA.SET_OUTPUT(1000000);
SET SERVEROUTPUT ON SIZE 1000000
exec host('/usr/bin/ls');
o
o FTP Client (GET and PUT files from PL/SQL)
/**
* Exceptions
*
*/
ctrl_exception EXCEPTION;
data_exception EXCEPTION;
/**
* Constants - FTP valid response codes
*
*/
/**
* FTP File record datatype
*
* Elements:
* localpath - full directory name in which the local file resides
or will reside
* Windows: 'd:\oracle\utl_file'
* UNIX: '/home/oracle/utl_file'
* filename - filename and extension for the file to be received or
sent
* changing the filename for the PUT or GET is currently
not allowed
* Examples: 'myfile.dat' 'myfile20021119.xml'
* remotepath - full directory name in which the local file will be
sent or the
* remote file exists. Should be in UNIX format
regardless of FTP server - '/one/two/three'
* filetype - reserved for future use, ignored in code
* transfer_mode - 'PUT' or 'GET'
* status - status of the transfer. 'ERROR' or 'SUCCESS'
* error_message - meaningful (hopefully) error message explaining
the reason for failure
* bytes_transmitted - how many bytes were sent/received
* trans_start - date/time the transmission started
* trans_end - date/time the transmission ended
*
*/
/**
* FTP File Table - used to store many files for transfer
*
*/
/**
* Internal convenience procedure for creating passive host IP
address
* and port number.
*
*/
/**
* Function used to validate FTP server responses based on the
* code passed in p_code. Reads single or multi-line responses.
*
*/
/**
* Function used to validate FTP server responses based on the
* code passed in p_code. Reads single or multi-line responses.
* Overloaded because some responses can have 2 valid codes.
*
*/
/**
* Procedure that handles the actual data transfer. Meant
* for internal package use. Returns information about the
* actual transfer.
*
*/
/**
* Function to handle FTP of many files.
* Returns TRUE if no batch-level errors occur.
* Returns FALSE if a batch-level error occurs.
*
* Parameters:
*
* p_error_msg - error message for batch level errors
* p_files - BRNC_FTP_PKG.t_ftp_rec table type. Accepts
* list of files to be transferred (may be any combination
of PUT or GET)
* returns the table updated with transfer status, error
message,
* bytes_transmitted, transmission start date/time and
transmission end
* date/time
* p_username - username for FTP server
* p_password - password for FTP server
* p_hostname - hostname or IP address of server Ex:
'ftp.oracle.com' or '127.0.0.1'
* p_port - port number to connect on. FTP is usually on 21, but
this may be overridden
* if the server is configured differently.
*
*/
/**
* Convenience function for single-file PUT
*
* Parameters:
* p_localpath - full directory name in which the local file resides
or will reside
* Windows: 'd:\oracle\utl_file'
* UNIX: '/home/oracle/utl_file'
* p_filename - filename and extension for the file to be received
or sent
* changing the filename for the PUT or GET is currently
not allowed
* Examples: 'myfile.dat' 'myfile20021119.xml'
* p_remotepath - full directory name in which the local file will
be sent or the
* remote file exists. Should be in UNIX format
regardless of FTP server - '/one/two/three'
* p_username - username for FTP server
* p_password - password for FTP server
* p_hostname - FTP server IP address or host name Ex:
'ftp.oracle.com' or '127.0.0.1'
* v_status - status of the transfer. 'ERROR' or 'SUCCESS'
* v_error_message - meaningful (hopefully) error message explaining
the reason for failure
* n_bytes_transmitted - how many bytes were sent/received
* d_trans_start - date/time the transmission started
* d_trans_end - date/time the transmission ended
* p_port - port number to connect to, default is 21
* p_filetype - always set to 'ASCII', reserved for future use,
ignored in code
*
*/
/**
* Convenience function for single-file GET
*
* Parameters:
* p_localpath - full directory name in which the local file resides
or will reside
* Windows: 'd:\oracle\utl_file'
* UNIX: '/home/oracle/utl_file'
* p_filename - filename and extension for the file to be received
or sent
* changing the filename for the PUT or GET is currently
not allowed
* Examples: 'myfile.dat' 'myfile20021119.xml'
* p_remotepath - full directory name in which the local file will
be sent or the
* remote file exists. Should be in UNIX format
regardless of FTP server - '/one/two/three'
* p_username - username for FTP server
* p_password - password for FTP server
* p_hostname - FTP server IP address or host name Ex:
'ftp.oracle.com' or '127.0.0.1'
* v_status - status of the transfer. 'ERROR' or 'SUCCESS'
* v_error_message - meaningful (hopefully) error message explaining
the reason for failure
* n_bytes_transmitted - how many bytes were sent/received
* d_trans_start - date/time the transmission started
* d_trans_end - date/time the transmission ended
* p_port - port number to connect to, default is 21
* p_filetype - always set to 'ASCII', reserved for future use,
ignored in code
*
*/
END BRNC_FTP_PKG;
/
CREATE OR REPLACE PACKAGE BODY BRNC_FTP_PKG
AS
/***********************************************************************
******
** Create the passive host IP and port number to connect to
**
************************************************************************
*****/
BEGIN
p_pasv_host :=
REPLACE(SUBSTR(v_pasv_cmd,1,INSTR(v_pasv_cmd,',',1,4)-1),',','.');
n_port_dec :=
TO_NUMBER(SUBSTR(v_pasv_cmd,INSTR(v_pasv_cmd,',',1,4)+1,
(INSTR(v_pasv_cmd,',',1,5)-(INSTR(v_pasv_cmd,',',1,4)+1))));
n_port_add :=
TO_NUMBER(SUBSTR(v_pasv_cmd,INSTR(v_pasv_cmd,',',1,5)+1,LENGTH(v_pasv_cm
d)-INSTR(v_pasv_cmd,',',1,5)));
p_pasv_port := (n_port_dec*256) + n_port_add;
EXCEPTION
WHEN OTHERS
THEN
--DBMS_OUTPUT.PUT_LINE(SQLERRM);
RAISE;
END CREATE_PASV;
/***********************************************************************
******
** Read a single or multi-line reply from the FTP server and
validate
** it against the code passed in p_code.
**
** Return TRUE if reply code matches p_code, FALSE if it doesn't or
error
** occurs
**
** Send full server response back to calling procedure
************************************************************************
*****/
/***********************************************************************
******
** Reads a single or multi-line reply from the FTP server
**
** Return TRUE if reply code matches p_code1 or p_code2,
** FALSE if it doesn't or error occurs
**
** Send full server response back to calling procedure
************************************************************************
*****/
/***********************************************************************
******
** Handles actual data transfer. Responds with status, error
message, and
** transfer statistics.
**
** Potential errors could be with connection or file i/o
**
************************************************************************
*****/
BEGIN
v_status := 'SUCCESS';
v_error_message := ' ';
n_bytes_transmitted := 0;
IF UPPER(v_tsfr_mode) = 'PUT'
THEN
v_mode := 'r';
v_tsfr_cmd := 'STOR ';
u_data_con := UTL_TCP.OPEN_CONNECTION(v_host,n_port);
/** Open the local file to read and transfer data **/
u_filehandle := UTL_FILE.FOPEN(v_localpath,v_filename,v_mode);
/** Send the STOR command to tell the server we're going to
upload a file **/
n_bytes := UTL_TCP.WRITE_LINE(u_ctrl_con,v_tsfr_cmd||
v_filename);
IF
VALIDATE_REPLY(u_ctrl_con,TSFR_START_CODE1,TSFR_START_CODE2,v_reply) =
FALSE
THEN
RAISE ctrl_exception;
END IF;
d_trans_start := SYSDATE;
IF UPPER(v_tsfr_mode) = 'PUT'
THEN
LOOP
BEGIN
UTL_FILE.GET_LINE(u_filehandle,v_buffer);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
EXIT;
END;
n_bytes := UTL_TCP.WRITE_LINE(u_data_con,v_buffer);
n_bytes_transmitted := n_bytes_transmitted + n_bytes;
END LOOP;
EXCEPTION
WHEN UTL_TCP.END_OF_INPUT
THEN
EXIT;
END;
END LOOP;
END IF;
--UTL_TCP.FLUSH(u_data_con);
d_trans_end := SYSDATE;
UTL_FILE.FCLOSE(u_filehandle);
UTL_TCP.CLOSE_CONNECTION(u_data_con);
IF VALIDATE_REPLY(u_ctrl_con,TSFR_END_CODE,v_reply) = FALSE
THEN
RAISE ctrl_exception;
END IF;
EXCEPTION
WHEN ctrl_exception
THEN
v_status := v_err_status;
v_error_message := v_reply;
IF UTL_FILE.IS_OPEN(u_filehandle)
THEN
UTL_FILE.FCLOSE(u_filehandle);
END IF;
UTL_TCP.CLOSE_CONNECTION(u_data_con);
WHEN UTL_FILE.invalid_path
THEN
v_status := v_err_status;
v_error_message := 'Directory '||v_localpath||' is not available
to UTL_FILE. Check the init.ora file for valid UTL_FILE directories.';
UTL_TCP.CLOSE_CONNECTION(u_data_con);
WHEN UTL_FILE.invalid_operation
THEN
v_status := v_err_status;
IF UPPER(v_tsfr_mode) = 'PUT'
THEN
v_error_message := 'The file '||V_filename||' in the
directory '||v_localpath||' could not be opened for reading.';
END IF;
IF UTL_FILE.IS_OPEN(u_filehandle)
THEN
UTL_FILE.FCLOSE(u_filehandle);
END IF;
UTL_TCP.CLOSE_CONNECTION(u_data_con);
WHEN UTL_FILE.read_error
THEN
v_status := v_err_status;
v_error_message := 'The system encountered an error while trying
to read '||v_filename||' in the directory '||v_localpath;
IF UTL_FILE.IS_OPEN(u_filehandle)
THEN
UTL_FILE.FCLOSE(u_filehandle);
END IF;
UTL_TCP.CLOSE_CONNECTION(u_data_con);
WHEN UTL_FILE.write_error
THEN
v_status := v_err_status;
v_error_message := 'The system encountered an error while trying
to write to '||v_filename||' in the directory '||v_localpath;
IF UTL_FILE.IS_OPEN(u_filehandle)
THEN
UTL_FILE.FCLOSE(u_filehandle);
END IF;
UTL_TCP.CLOSE_CONNECTION(u_data_con);
WHEN UTL_FILE.internal_error
THEN
v_status := v_err_status;
v_error_message := 'The UTL_FILE package encountered an
unexpected internal system error.';
IF UTL_FILE.IS_OPEN(u_filehandle)
THEN
UTL_FILE.FCLOSE(u_filehandle);
END IF;
UTL_TCP.CLOSE_CONNECTION(u_data_con);
WHEN OTHERS
THEN
v_status := v_err_status;
v_error_message := SQLERRM;
IF UTL_FILE.IS_OPEN(u_filehandle)
THEN
UTL_FILE.FCLOSE(u_filehandle);
END IF;
UTL_TCP.CLOSE_CONNECTION(u_data_con);
END TRANSFER_ASCII;
/***********************************************************************
******
** Handles connection to host and FTP of multiple files
** Files can be any combination of PUT and GET
**
************************************************************************
*****/
invalid_transfer EXCEPTION;
BEGIN
u_ctrl_con := UTL_TCP.OPEN_CONNECTION(v_hostname,n_port);
IF VALIDATE_REPLY(u_ctrl_con,CONNECT_CODE,v_reply) = FALSE
THEN
RAISE ctrl_exception;
END IF;
FOR i IN p_files.FIRST..p_files.LAST
LOOP
IF p_files.EXISTS(i)
THEN
BEGIN
n_byte_count := UTL_TCP.WRITE_LINE(u_ctrl_con,'CWD
'||p_files(i).remotepath);
IF VALIDATE_REPLY(u_ctrl_con,CWD_CODE,v_reply) =
FALSE
THEN
RAISE ctrl_exception;
END IF;
n_byte_count := UTL_TCP.WRITE_LINE(u_ctrl_con,'TYPE
I');
IF VALIDATE_REPLY(u_ctrl_con,TYPE_CODE,v_reply) =
FALSE
THEN
RAISE ctrl_exception;
END IF;
n_byte_count :=
UTL_TCP.WRITE_LINE(u_ctrl_con,'PASV');
IF VALIDATE_REPLY(u_ctrl_con,PASV_CODE,v_reply) =
FALSE
THEN
RAISE ctrl_exception;
END IF;
CREATE_PASV(SUBSTR(v_reply,INSTR(v_reply,'(',1,1)+1,INSTR(v_reply,')',1,
1)-INSTR(v_reply,'(',1,1)-1),v_pasv_host,n_pasv_port);
IF UPPER(p_files(i).transfer_mode) = 'PUT'
THEN
TRANSFER_ASCII(u_ctrl_con,
p_files(i).localpath,
p_files(i).filename,
v_pasv_host,
n_pasv_port,
p_files(i).transfer_mode,
p_files(i).status,
p_files(i).error_message,
p_files(i).bytes_transmitted,
p_files(i).trans_start,
p_files(i).trans_end);
EXCEPTION
WHEN ctrl_exception
THEN
p_files(i).status := 'ERROR';
p_files(i).error_message := v_reply;
WHEN invalid_transfer
THEN
p_files(i).status := 'ERROR';
p_files(i).error_message := 'Invalid transfer
method. Use PUT or GET.';
END;
END IF;
END LOOP;
/** Don't need to validate QUIT, just close the connection **/
UTL_TCP.CLOSE_CONNECTION(u_ctrl_con);
RETURN TRUE;
EXCEPTION
WHEN ctrl_exception
THEN
p_error_msg := v_reply;
UTL_TCP.CLOSE_ALL_CONNECTIONS;
RETURN FALSE;
WHEN OTHERS
THEN
p_error_msg := SQLERRM;
UTL_TCP.CLOSE_ALL_CONNECTIONS;
RETURN FALSE;
END FTP_MULTIPLE;
/***********************************************************************
******
** Convenience function for single-file PUT
** Formats file information for FTP_MULTIPLE function and calls it.
**
************************************************************************
*****/
b_ftp := FTP_MULTIPLE(v_err_msg,
t_files,
v_username,
v_password,
v_hostname,
n_port);
IF b_ftp = FALSE
THEN
v_status := 'ERROR';
v_error_message := v_err_msg;
RETURN FALSE;
ELSIF b_ftp = TRUE
THEN
v_status := t_files(1).status;
v_error_message := t_files(1).error_message;
n_bytes_transmitted := t_files(1).bytes_transmitted;
d_trans_start := t_files(1).trans_start;
d_trans_end := t_files(1).trans_end;
RETURN TRUE;
END IF;
EXCEPTION
WHEN OTHERS
THEN
v_status := 'ERROR';
v_error_message := SQLERRM;
RETURN FALSE;
--DBMS_OUTPUT.PUT_LINE(SQLERRM);
END PUT;
/***********************************************************************
******
** Convenience function for single-file GET
** Formats file information for FTP_MULTIPLE function and calls it.
**
************************************************************************
*****/
END BRNC_FTP_PKG;
/
o
o Send e-mail messages from PL/SQL (using UTL_TCP)
-- Examples:
set serveroutput on
DECLARE
v_From VARCHAR2(80) := 'oracle@mycompany.com';
v_Recipient VARCHAR2(80) := 'test@mycompany.com';
v_Subject VARCHAR2(80) := 'test subject';
v_Mail_Host VARCHAR2(30) := 'mail.mycompany.com';
v_Mail_Conn utl_smtp.Connection;
crlf VARCHAR2(2) := chr(13)||chr(10);
BEGIN
v_Mail_Conn := utl_smtp.Open_Connection(v_Mail_Host, 25);
utl_smtp.Helo(v_Mail_Conn, v_Mail_Host);
utl_smtp.Mail(v_Mail_Conn, v_From);
utl_smtp.Rcpt(v_Mail_Conn, v_Recipient);
utl_smtp.Data(v_Mail_Conn,
'Date: ' || to_char(sysdate, 'Dy, DD Mon YYYY hh24:mi:ss') || crlf
||
'From: ' || v_From || crlf ||
'Subject: '|| v_Subject || crlf ||
'To: ' || v_Recipient || crlf ||
'-------SECBOUND'|| crlf ||
'Content-Type: text/plain;'|| crlf ||
'Content-Transfer_Encoding: 7bit'|| crlf ||
crlf ||
'some message text'|| crlf || -- Message body
'more message text'|| crlf ||
crlf ||
'-------SECBOUND'|| crlf ||
'Content-Type: text/plain;'|| crlf ||
' name="excel.csv"'|| crlf ||
'Content-Transfer_Encoding: 8bit'|| crlf ||
'Content-Disposition: attachment;'|| crlf ||
' filename="excel.csv"'|| crlf ||
crlf ||
'CSV,file,attachement'|| crlf || -- Content of attachment
crlf ||
utl_smtp.Quit(v_mail_conn);
EXCEPTION
WHEN utl_smtp.Transient_Error OR utl_smtp.Permanent_Error then
raise_application_error(-20000, 'Unable to send mail: '||sqlerrm);
END;
/
o
o Mailmerge: Merge data from the table/view data sources into a custom template
/
************************************************************************
**************
*
* TITLE......: Mail Merge
* DESCRIPTION: Merge data from the data source into a custom template
*
* AUTHOR.....: Claudiu Ariton
* DATE.......: april 2004
*
* Modifications
*
************************************************************************
**************/
function mail_merge(
p_message in varchar2,
p_argv in argv ,
p_esc_char in varchar2 default '$') return varchar2;
end mail_merge;
/
--
------------------------------------------------------------------------
-----------
-- Set_ctx - set generic context
--
------------------------------------------------------------------------
-----------
procedure set_ctx( p_name in varchar2, p_value in varchar2,p_ctx in
varchar2 default 'mm_ctx' )
as
begin
dbms_session.set_context( p_ctx, p_name, p_value, USER);
end;
--
------------------------------------------------------------------------
-----------
-- mail_merge - Merge data from list of vaalues into a custom template
--
------------------------------------------------------------------------
-----------
function mail_merge(
p_message in varchar2,
p_argv in argv ,
p_esc_char in varchar2 default '$') return varchar2 is
--
l_message long := null;
l_str long := p_message;
l_idx number := 1;
l_ptr number := 1;
l_poz varchar2(10);
l_on number;
begin
if nvl( instr( p_message, p_esc_char ), 0 ) = 0 and
nvl( instr( p_message, '\' ), 0 ) = 0 then
return p_message;
end if;
loop
l_on:=0;
l_ptr := instr( l_str, p_esc_char );
exit when l_ptr = 0 or l_ptr is null;
l_message := l_message || substr( l_str, 1, l_ptr-1 );
l_str := substr( l_str, l_ptr+1 );
l_poz:=null;
while substr( l_str, 1, 1 ) in
('0','1','2','3','4','5','6','7','8','9') loop
l_poz:=l_poz||substr( l_str, 1, 1 );
l_str := substr( l_str, 2 );
l_on:=1;
end loop;
begin
l_message := l_message || p_argv(to_number(l_poz));
exception
when no_data_found then l_message := l_message || '<unknown>';
when others then null;
end;
end loop;
--
------------------------------------------------------------------------
-----------
-- mail_merge - Merge data from a table/viiew into a custom template
--
------------------------------------------------------------------------
-----------
Procedure generic_mail_merge(p_ttext varchar2, p_query in varchar2,
p_date_format in varchar2 default 'dd-MON-yyyy hh24:mi:ss',
p_bindid in number default null,p_list_val in argv default emptyargv)
is
l_theCursor integer default dbms_sql.open_cursor;
l_defcolumn varchar2(4000);
l_columnValue argv;
l_status integer;
l_descTbl dbms_sql.desc_tab;
l_colCnt number;
v_result varchar2(4000);
v_pkid number;
begin
execute immediate
'alter session set
nls_date_format='''|| p_date_format ||'''';
dbms_sql.describe_columns
( l_theCursor, l_colCnt, l_descTbl );
-- seteaza context
begin
for i in 1..p_list_val.count loop
set_ctx('param'||to_char(i),p_list_val(i));
end loop;
exception
when others then null;
end;
l_status := dbms_sql.execute(l_theCursor);
while ( dbms_sql.fetch_rows(l_theCursor) > 0 ) loop
for i in 1 .. l_colCnt loop
dbms_sql.column_value
( l_theCursor, i, l_columnValue(i) );
if upper(l_descTbl(i).col_name)='PKID' then
v_pkid:=to_number(l_columnValue(i));
end if;
end loop;
v_result:=mail_merge( p_ttext,l_columnValue);
insert into TEMP_MAIL_MERGE(pkid,result) values
(v_pkid,v_result);
end loop;
dbms_sql.close_cursor( l_theCursor);
execute immediate
'alter session set nls_date_format=''dd-MON-rr'' ';
exception
when others then
if dbms_sql.is_open(l_theCursor) then
dbms_sql.close_cursor( l_theCursor);
end if;
execute immediate
'alter session set nls_date_format=''dd-MON-rr'' ';
raise;
end;
end mail_merge;
/
o
o Read an Internet Web pages from PL/SQL
DECLARE
t_c1_tname user_tables.table_name%TYPE;
t_command varchar2(200);
t_cid integer;
t_total_records number(10);
stat integer;
row_count integer;
t_limit integer := 0; -- Only show tables with more rows
cursor c1 is select table_name from user_tables order by table_name;
BEGIN
t_limit := 0;
open c1;
loop
fetch c1 into t_c1_tname;
exit when c1%NOTFOUND;
t_command := 'SELECT COUNT(0) FROM '||t_c1_tname;
t_cid := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(t_cid,t_command,dbms_sql.native);
DBMS_SQL.DEFINE_COLUMN(t_cid,1,t_total_records);
stat := DBMS_SQL.EXECUTE(t_cid);
row_count := DBMS_SQL.FETCH_ROWS(t_cid);
DBMS_SQL.COLUMN_VALUE(t_cid,1,t_total_records);
if t_total_records > t_limit then
DBMS_OUTPUT.PUT_LINE(rpad(t_c1_tname,55,' ')||
to_char(t_total_records,'99999999')||'
record(s)');
end if;
DBMS_SQL.CLOSE_CURSOR(t_cid);
end loop;
close c1;
END;
/
o
o List tables from schema with more than X rows
o
o Replace all occurences of a substring with another substring
create or replace function strreplace(str varchar2, from_str varchar2,
to_str varchar2)
return varchar2
AS
str_temp varchar2(4000);
str_pos number := instr(str, from_str);
BEGIN
str_temp := str;
while ( str_pos > 0 ) loop
str_temp := substr(str_temp, 0, str_pos-1) || to_str ||
substr(str_temp, str_pos + length(from_str));
str_pos := instr(str_temp, from_str);
end loop;
return str_temp;
END;
/
show errors
-- Examples
-- Examples:
Select number_conversion(-3786.9899876) from dual;
Select number_conversion(7685.78788) from dual;
Select number_conversion(7678) from dual;
o
o Print cheque amounts in Indian Style
if ( N = 0 ) THEN
X := 'ZERO ';
elsif ( N <= 99999 ) THEN
X := to_char(to_date(N,'J'),'JSP') || ' ';
else
if ( L = 6 ) then
X1 := to_char(to_date(to_number(substr(N, 1, L -
5)),'J'),'JSP') || ' LAKH ';
else
if ( to_number(substr(N, L - 5 -1, 2)) = 0 ) then
X1 := '';
else
X1 := to_char(to_date(to_number(substr(N, L - 5 - 1,
2)),'J'),'JSP') || ' LAKH ';
end if;
if ( L >= 8 ) then
C1 := to_char(to_date(to_number(substr(N, 1, L-
7)),'J'),'JSP')||' CRORE ';
end if;
end if;
end if;
if ( N = 0 OR N = 1 ) THEN
DBMS_OUTPUT.PUT_LINE(N||' => '||X||'RUPEE ONLY');
else
DBMS_OUTPUT.PUT_LINE(N||' => '||C1||X1||X||'RUPEES ONLY');
end if;
end if;
END CHEQ;
/
show errors
o
o NYSIIS function (an improvement on SoundeX)
v_sub varchar2(300);
v_length number(10);
v_textin varchar2(300);
v_key varchar2(1);
begin
SELECT UPPER ( v_text ) into v_textin from dual;
dbms_output.put_line( 'Entered surname :' || v_textin);
dbms_output.put_line( ' [1] remove all S and Z chars from the end of
the surname ' );
LOOP
SELECT SUBSTR ( v_textin , (length (v_textin))) into v_sub from
dual;
dbms_output.put_line('Last letter :' || v_sub);
if v_sub = 'S' OR v_sub = 'Z' THEN
SELECT SUBSTR ( v_textin , 1 , (length (v_textin) -1 )) into
v_textin from dual ;
dbms_output.put_line('As last letter s or z drop last letter
giving :' || v_textin || ' and check new last letter');
else
dbms_output.put_line('Last letter not s or z completed step 1');
EXIT;
end if;
END LOOP;
dbms_output.put_line('Step 1 completed giving :' || v_textin );
RETURN( v_textin );
end NYSIIS;
/
o
o Converts a string of text into seperate soundex values
rem
------------------------------------------------------------------------
--
rem Filename: M_SOUNDEX.SQL
rem Purpose: Converts a string of text into seperate soundex values.
Treating
rem it as space deliminated words. Useful when searching text
strings for a sounds like.
rem
rem Notes: USEAGE "select M_SOUNDEX('the cat sat on the mat') from
dual;"
rem M_SOUNDEX('THECATSATONTHEMAT')
rem -----------------------------------
rem T000 C300 S300 O500 T000 M300
rem
rem
rem select M_SOUNDEX('the cat sat on the mat') from dual where
rem M_SOUNDEX('the cat sat on the mat') like ('%' || SOUNDEX('cot') ||
'%');
rem
rem Date: 01-Mar-2005
rem Author: Trevor Fairhurst, trevgf@yahoo.com
rem
------------------------------------------------------------------------
--
o
o Package to generate HTML-type documentation for Oracle objects
o 1) REATE OR REPLACE PACKAGE documentator
o AS
o
o /* **************************************
o Set Dependencies
o * **************************************/
o PROCEDURE getRefObjects(
o IN_OBJECT VARCHAR2,
o IN_OBJECT_TYPE VARCHAR2);
o
o /* **************************************
o Get Table Dependencies
o * **************************************/
o PROCEDURE getTblRefObjects(
o IN_OBJECT VARCHAR2,
o IN_OBJECT_TYPE VARCHAR2);
o
o /* **************************************
o Get common object details
o * **************************************/
o PROCEDURE getTopObjectDetails(
o IN_OBJECT VARCHAR2,
o IN_OBJECT_TYPE VARCHAR2);
o
o /* **************************************
o Set Doc Header
o * **************************************/
o PROCEDURE setDocHeader(
o IN_OBJECT VARCHAR2,
o IN_OBJECT_TYPE VARCHAR2);
o
o /* **************************************
o Get all privileges
o * **************************************/
o PROCEDURE getUnitAllPrivs(IN_OBJECT VARCHAR2);
o
o /* **************************************
o Initialize variables
o * **************************************/
o PROCEDURE initDoc(IN_OBJECT VARCHAR2);
o
o /* **************************************
o Finish documents preparation and send emails
o * **************************************/
o PROCEDURE finishDoc(
o IN_OBJECT VARCHAR2,
o IN_FILE_NAME VARCHAR2,
o IN_EMAIL VARCHAR2);
o
o /* **************************************
o Prepare document for Procedure/Function/Package
o * **************************************/
o PROCEDURE getPkgDoc(
o IN_OBJECT VARCHAR2,
o IN_FILE_NAME VARCHAR2);
o
o /* **************************************
o Prepare document for Table
o * **************************************/
o PROCEDURE getTblDoc(
o IN_OBJECT VARCHAR2,
o IN_OBJECT_TYPE VARCHAR2,
o IN_FILE_NAME VARCHAR2);
o
o /* **************************************
o Main procedure to generate document
o * **************************************/
o PROCEDURE generateDocInfo(
o IN_OBJECT VARCHAR2,
o IN_FILE_NAME VARCHAR2,
o IN_EMAIL VARCHAR2);
o
o /* **************************************
o Main procedure to generate document for all objects for the given object type
o * **************************************/
o PROCEDURE generateDocInfoByType(
o IN_OBJECT_TYPE VARCHAR2,
o IN_FILE_NAME VARCHAR2,
o IN_EMAIL VARCHAR2);
o
o /* **************************************
o Main procedure to generate document for all objects for the given object types
o * **************************************/
o PROCEDURE generateDocInfoByTypes(
o IN_OBJECT_TYPE VARCHAR2,
o IN_FILE_NAME VARCHAR2,
o IN_EMAIL VARCHAR2);
o
o /* **************************************
o Get list of procedures/functions with arguments
o * **************************************/
o PROCEDURE getArgumentsList(IN_OBJECT VARCHAR2);
o
o /* **************************************
o Get trigger columns
o * **************************************/
o PROCEDURE getTriggerColumns(IN_OBJECT VARCHAR2);
o
o /* **************************************
o Get trigger details
o * **************************************/
o PROCEDURE getTriggerDetails(IN_OBJECT VARCHAR2);
o
o /* **************************************
o Get PL/SQL unit Source
o * **************************************/
o PROCEDURE getUnitSource(
o IN_OBJECT VARCHAR2,
o IN_OBJECT_TYPE VARCHAR2);
o
o /* **************************************
o Get type status
o * **************************************/
o PROCEDURE getTypeStatus(
o IN_OBJECT VARCHAR2,
o IN_OBJECT_TYPE VARCHAR2);
o
o /* **************************************
o Get type attributes
o * **************************************/
o PROCEDURE getTypeAttrs(IN_OBJECT VARCHAR2);
o
o /* **************************************
o Get list of type methods
o * **************************************/
o PROCEDURE getTypeMethods(IN_OBJECT VARCHAR2);
o
o /* **************************************
o Get table columns
o * **************************************/
o PROCEDURE getTblCols(IN_OBJECT VARCHAR2);
o
o /* **************************************
o Get Table Constraints
o * **************************************/
o PROCEDURE getTblConstraints(IN_OBJECT VARCHAR2);
o
o /* **************************************
o Get all Table privileges
o * **************************************/
o PROCEDURE getTblPrivs(IN_OBJECT VARCHAR2);
o
o /* **************************************
o Get Table Indexes
o * **************************************/
o PROCEDURE getTblIndexes(IN_OBJECT VARCHAR2);
o
o PROCEDURE sendEmailAttachments(
o IN_FROM_EMAIL VARCHAR2,
o IN_TO_EMAILS VARCHAR2,
o IN_CC_EMAILS VARCHAR2,
o IN_SUBJ VARCHAR2,
o IN_TEXT CLOB,
o IN_MIME_TYPE VARCHAR2 DEFAULT 'text/plain',
o IN_FILENAME_1 VARCHAR2,
o IN_CONTENT_1 CLOB,
o IN_FILENAME_2 VARCHAR2 DEFAULT NULL,
o IN_CONTENT_2 CLOB DEFAULT NULL,
o IN_FILENAME_3 VARCHAR2 DEFAULT NULL,
o IN_CONTENT_3 CLOB DEFAULT NULL);
o
o END documentator;
o /
o show error
2) /*
************************************************************************
************
Package to generate HTML-type documentation for Oracle objects.
Supported objects:
Package and Package body
Function
Procedure
Trigger
User Type
Table
View
Prerequisites:
UTL_SMTP package installed in DB
Active/installed option Oracle JServer/JVM
To call:
a) documentator.generateDocInfo( IN_OBJECT, IN_FILE_NAME,
IN_EMAIL)
where
IN_OBJECT - object name
IN_FILE_NAME - output file name which will be used as base
for output file names.
IN_EMAIL - TO email
Example:
documentator.generateDocInfo('EMP', 'emp.htm',
'email@your_domain.com');
b) documentator.generateDocInfoByType( IN_OBJECT_TYPE,
IN_FILE_NAME, IN_EMAIL)
where
IN_OBJECT_TYPE - object type (ex. PACKAGE, etc..) Package will
generate documentation for all objects for the given type
IN_FILE_NAME - output file name which will be used as base
for output file names.
IN_EMAIL - TO email
Example:
documentator.generateDocInfoByType('TABLE', 'table.htm',
'email@your_domain.com');
c) documentator.generateDocInfoByTypes(<TYPES>, IN_FILE_NAME,
IN_EMAIL)
where
IN_OBJECT_TYPE - objects types (PACKAGE, PROCEDURE, etc..)
comma separated.
IN_FILE_NAME - output file name which will be used as base
for output file names.
IN_EMAIL - TO email
example:
exec documentator.generateDocInfoByTypes('FUNCTION, PROCEDURE,
PACKAGE, TRIGGER, TYPE, TABLE, VIEW', 'objects.htm',
'email@your_domain.com');
will prepare doc for all passed object types in a current schema
Note:
Oracle 8i view user_constraints does not contain column
INDEX_NAME, so it populates with ' '
Created:
Oleg Savkin toyway@yahoo.com 12/05/2005
Modified:
Oleg Savkin toyway@yahoo.com 01/24/2006 Modified to use in Oracle
8i
*
************************************************************************
************/
CREATE OR REPLACE PACKAGE BODY documentator
AS
docBody CLOB;
main_page CLOB;
ref_page CLOB;
gv_schema VARCHAR2(30);
gv_db_name VARCHAR2(30);
gv_user VARCHAR2(30);
gv_version VARCHAR2(255);
/******************************************
Private email procedures/functions
******************************************/
/* ******************************************************************
-- Private procedure
-- procedure to parse text with Types
-- and store them in type_index type
* ******************************************************************/
PROCEDURE splitType(IN_TEXT VARCHAR2)
IS
lv_in_text VARCHAR2(4000);
lv_out_text VARCHAR2(4000);
ln_divider VARCHAR2(1) := ',';
ln_pos PLS_INTEGER;
ln_word_cnt PLS_INTEGER;
BEGIN
type_index.DELETE;
/* ******************************************************************
-- Private procedure
-- procedure to parse text with Email IDs
-- and store them in email_index type
* ******************************************************************/
PROCEDURE splitEmail(IN_TEXT VARCHAR2)
IS
lv_in_text VARCHAR2(4000);
lv_out_text VARCHAR2(4000);
ln_divider VARCHAR2(1) := ',';
ln_pos PLS_INTEGER;
ln_word_cnt PLS_INTEGER;
BEGIN
email_index.DELETE;
END splitEmail;
/*
************************************************************************
****
Write email body in email
*
************************************************************************
****/
PROCEDURE setEmailBody(
IN_CONNECTION IN OUT NOCOPY UTL_SMTP.CONNECTION,
IN_TEXT CLOB)
AS
ln_length PLS_INTEGER;
ln_offset PLS_INTEGER;
lv_text VARCHAR2(32767);
ln_amount BINARY_INTEGER := 32767;
ln_total number;
BEGIN
ln_length := dbms_lob.getlength( IN_TEXT );
ln_offset := 1;
LOOP
BEGIN
DBMS_LOB.READ(IN_TEXT, ln_amount, ln_offset, lv_text);
EXCEPTION
WHEN no_data_found
THEN
EXIT;
END;
utl_smtp.write_data(IN_CONNECTION, lv_text);
ln_offset := ln_offset + ln_amount;
END LOOP;
EXCEPTION
WHEN OTHERS
THEN
RAISE;
END setEmailBody;
/*
************************************************************************
****
start email with attachments
*
************************************************************************
****/
FUNCTION setBeginAttachEmail(
IN_FROM_EMAIL VARCHAR2,
IN_TO_EMAILS VARCHAR2,
IN_CC_EMAILS VARCHAR2,
IN_SUBJ VARCHAR2,
IN_TEXT CLOB,
IN_MIME_TYPE VARCHAR2 DEFAULT 'text/plain')
RETURN UTL_SMTP.CONNECTION
AS
conn_ UTL_SMTP.CONNECTION; -- Customize the SMTP host, port and
your domain name below.
smtp_host VARCHAR2(256) := 'localhost';
smtp_port PLS_INTEGER := 25;
lv_sender VARCHAR2(2000);
lv_to_email VARCHAR2(2000);
lv_cc_email VARCHAR2(2000);
lv_subj VARCHAR2(500);
lv_msg VARCHAR2(32767);
boundary CONSTANT VARCHAR2(256) :=
'CES.Boundary.DACA587499938898';
BEGIN
-- Set up connection
conn_:= utl_smtp.open_connection( smtp_host, smtp_port );
utl_smtp.helo( conn_, smtp_host );
IF IN_FROM_EMAIL IS NULL
THEN
lv_sender := 'documentator@your_domain.com';
ELSE
lv_sender := IN_FROM_EMAIL;
END IF;
utl_smtp.open_data(conn_);
RETURN conn_;
EXCEPTION
WHEN others
THEN
RAISE;
END setBeginAttachEmail;
/*
************************************************************************
****
End email session
*
************************************************************************
****/
PROCEDURE setEndEmail( IN_CONNECTION IN OUT NOCOPY
UTL_SMTP.CONNECTION)
AS
BEGIN
-- closing connection
utl_smtp.close_data( IN_CONNECTION );
utl_smtp.quit( IN_CONNECTION );
EXCEPTION
WHEN OTHERS
THEN
RAISE;
END setEndEmail;
/* **************************************
Get common object details
* **************************************/
PROCEDURE getTopObjectDetails(
IN_OBJECT VARCHAR2,
IN_OBJECT_TYPE VARCHAR2)
IS
lv_created VARCHAR2(30);
lv_last_ddl_time VARCHAR2(30);
lv_status VARCHAR2(30);
BEGIN
-- page header
DBMS_LOB.WRITE(docBody, LENGTH( '<HTML>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<HTML>'||CHR(10));
END getTopObjectDetails;
/* **************************************
Set Dependencies
* **************************************/
PROCEDURE getRefObjects(
IN_OBJECT VARCHAR2,
IN_OBJECT_TYPE VARCHAR2)
IS
is_reference BOOLEAN;
BEGIN
-- ************************************************
-- get Referencing
DBMS_LOB.WRITE(docBody, LENGTH( '<TABLE WIDTH=100% CELLPADDING=3
BORDER=2>'||CHR(10) ), DBMS_LOB.GETLENGTH( docBody)+1, '<TABLE
WIDTH=100% CELLPADDING=3 BORDER=2>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD BGCOLOR=#ccccff><FONT
FACE="ARIAL" SIZE=2>Referencing Objects</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD BGCOLOR=#ccccff><FONT FACE="ARIAL"
SIZE=2>Referencing Objects</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TABLE>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TABLE>'||CHR(10));
is_reference := FALSE;
FOR lrec IN (
SELECT
TRIM(referenced_owner||'.'||name) as object_name,
TRIM(type) as object_type
FROM ALL_DEPENDENCIES
WHERE referenced_name = IN_OBJECT
AND name <> IN_OBJECT
UNION ALL
SELECT owner||'.'||synonym_name as object_name,
'SYNONYM' as object_type
FROM all_synonyms
WHERE table_name = IN_OBJECT
ORDER BY 2)
LOOP
is_reference := TRUE;
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.object_name||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.object_name||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.object_type||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.object_type||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END LOOP;
IF NOT is_reference
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>NOT FOUND</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END IF;
-- ************************************************
-- get Referenced
DBMS_LOB.WRITE(docBody, LENGTH( '<TABLE WIDTH=100% CELLPADDING=3
BORDER=2>'||CHR(10) ), DBMS_LOB.GETLENGTH( docBody)+1, '<TABLE
WIDTH=100% CELLPADDING=3 BORDER=2>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD BGCOLOR=#ccccff><FONT
FACE="ARIAL" SIZE=2>Referenced Objects</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD BGCOLOR=#ccccff><FONT FACE="ARIAL"
SIZE=2>Referenced Objects</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TABLE>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TABLE>'||CHR(10));
FOR lrec IN (
SELECT TRIM(referenced_owner||'.'||referenced_name) as
object_name,
DECODE(referenced_type, 'NON-EXISTENT', ' ',
TRIM(referenced_type)) as object_type
FROM all_dependencies
WHERE name = IN_OBJECT
AND referenced_name <> IN_OBJECT
AND type = IN_OBJECT_TYPE
ORDER BY 2, 1)
LOOP
is_reference := TRUE;
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.object_name||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.object_name||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.object_type||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.object_type||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END LOOP;
IF NOT is_reference
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>NOT FOUND</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END IF;
END getRefObjects;
/* **************************************
Get Table Dependencies
* **************************************/
PROCEDURE getTblRefObjects(
IN_OBJECT VARCHAR2,
IN_OBJECT_TYPE VARCHAR2)
IS
is_reference BOOLEAN;
BEGIN
-- ************************************************
-- get Referencing
DBMS_LOB.WRITE(docBody, LENGTH( '<TABLE WIDTH=100% CELLPADDING=3
BORDER=2>'||CHR(10) ), DBMS_LOB.GETLENGTH( docBody)+1, '<TABLE
WIDTH=100% CELLPADDING=3 BORDER=2>'||CHR(10));
is_reference := FALSE;
-- referencing
FOR lrec IN (
SELECT
TRIM(owner||'.'||name) as object_name,
TRIM(type) as object_type
FROM all_dependencies
WHERE referenced_name = IN_OBJECT
AND name <> IN_OBJECT
UNION ALL
SELECT owner||'.'||synonym_name as object_name,
'SYNONYM' as object_type
FROM all_synonyms
WHERE table_name = IN_OBJECT
UNION ALL
SELECT owner||'.'||index_name as object_name,
'INDEX' as object_type
FROM all_indexes
WHERE table_name = IN_OBJECT
ORDER BY 2)
LOOP
is_reference := TRUE;
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.object_name||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.object_name||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.object_type||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.object_type||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END LOOP;
IF NOT is_reference
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>NOT FOUND</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END IF;
-- referenced objects
DBMS_LOB.WRITE(docBody, LENGTH( '<TABLE WIDTH=100% CELLPADDING=3
BORDER=2>'||CHR(10) ), DBMS_LOB.GETLENGTH( docBody)+1, '<TABLE
WIDTH=100% CELLPADDING=3 BORDER=2>'||CHR(10));
is_reference := FALSE;
FOR lrec IN (
SELECT
TRIM(referenced_owner||'.'||referenced_name) as
object_name,
TRIM(referenced_type) as object_type
FROM all_dependencies
WHERE name = IN_OBJECT)
LOOP
is_reference := TRUE;
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.object_name||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.object_name||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.object_type||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.object_type||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END LOOP;
IF NOT is_reference
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>NOT FOUND</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END IF;
/* **************************************
Set Doc Header
* **************************************/
PROCEDURE setDocHeader(
IN_OBJECT VARCHAR2,
IN_OBJECT_TYPE VARCHAR2)
IS
lv_Code_Size PLS_INTEGER;
lv_created VARCHAR2(30);
lv_last_ddl_time VARCHAR2(30);
lv_status VARCHAR2(30);
BEGIN
-- Body info
DBMS_LOB.WRITE(docBody, LENGTH( '<TABLE WIDTH=100% CELLPADDING=2
BORDER=3>'||CHR(10) ), DBMS_LOB.GETLENGTH( docBody)+1, '<TABLE
WIDTH=100% CELLPADDING=2 BORDER=3>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD BGCOLOR=#ccccff
WIDTH=300><FONT FACE="ARIAL" SIZE=4>Information</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD BGCOLOR=#ccccff WIDTH=300><FONT
FACE="ARIAL" SIZE=4>Information</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TABLE>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TABLE>'||CHR(10));
END setDocHeader;
/* **************************************
Set Table Doc Header
* **************************************/
PROCEDURE setTblDocHeader(
IN_OBJECT VARCHAR2,
IN_OBJECT_TYPE VARCHAR2)
IS
lv_created VARCHAR2(30);
lv_last_ddl_time VARCHAR2(30);
lv_last_analyzed VARCHAR2(30);
lv_num_rows VARCHAR2(30);
lv_partitioned VARCHAR2(30);
lv_nested VARCHAR2(30);
lv_comment VARCHAR2(4000);
lv_status VARCHAR2(30);
BEGIN
IF IN_OBJECT_TYPE = 'TABLE'
THEN
SELECT TO_CHAR(last_analyzed,'MM/DD/YYYY HH24:MI:SS'),
TRIM(TO_CHAR( NVL(num_rows, 0), '999,999,999,999,999')),
partitioned,
nested
INTO lv_last_analyzed, lv_num_rows, lv_partitioned, lv_nested
FROM user_tables
WHERE table_name = IN_OBJECT;
-- Body info
DBMS_LOB.WRITE(docBody, LENGTH( '<TABLE WIDTH=100% CELLPADDING=2
BORDER=3>'||CHR(10) ), DBMS_LOB.GETLENGTH( docBody)+1, '<TABLE
WIDTH=100% CELLPADDING=2 BORDER=3>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD BGCOLOR=#ccccff
WIDTH=300><FONT FACE="ARIAL" SIZE=4>Information</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD BGCOLOR=#ccccff WIDTH=300><FONT
FACE="ARIAL" SIZE=4>Information</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TABLE>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TABLE>'||CHR(10));
END setTblDocHeader;
/* **************************************
Get all Unit privileges
* **************************************/
PROCEDURE getUnitAllPrivs(IN_OBJECT VARCHAR2)
IS
is_privs BOOLEAN;
ref_c VARCHAR2(4000) :=
'SELECT
(SELECT DECODE(privilege, ''DEBUG'', ''Y'')
FROM all_tab_privs
WHERE table_name = :1
AND grantee = :2
AND privilege = ''DEBUG'') deb,
(SELECT DECODE(privilege, ''EXECUTE'', ''Y'')
FROM all_tab_privs
WHERE table_name = :3
AND grantee = :4
AND privilege = ''EXECUTE'') exe
FROM DUAL';
privs_data_deb VARCHAR2(30);
privs_data_exe VARCHAR2(30);
BEGIN
FOR lrec IN (
SELECT DISTINCT grantee
FROM all_tab_privs
WHERE table_name = IN_OBJECT)
LOOP
is_privs := TRUE;
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.grantee||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.grantee||'</FONT></TD>'||CHR(10));
END LOOP;
CLOSE c_privs_c;
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END LOOP;
IF NOT is_privs
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END IF;
/* **************************************
Initialize variables
* **************************************/
PROCEDURE initDoc(IN_OBJECT VARCHAR2)
IS
BEGIN
-- main page
DBMS_LOB.CREATETEMPORARY(main_page, TRUE); -- initialize
DBMS_LOB.WRITE(main_page, LENGTH( '<HTML>'||CHR(10) ), 1,
'<HTML>'||CHR(10));
-- body
DBMS_LOB.CREATETEMPORARY(docBody, TRUE); -- initialize
DBMS_LOB.WRITE(docBody, 1, 1, CHR(10));
END initDoc;
/* **************************************
Finish documents preparation and send emails
* **************************************/
PROCEDURE finishDoc(
IN_OBJECT VARCHAR2,
IN_FILE_NAME VARCHAR2,
IN_EMAIL VARCHAR2)
IS
sessiontimezone VARCHAR2(10) := '';
BEGIN
END finishDoc;
/* **************************************
Prepare document for Procedure/Function/Package
* **************************************/
PROCEDURE getPkgDoc(
IN_OBJECT VARCHAR2,
IN_FILE_NAME VARCHAR2)
IS
BEGIN
FOR lrec IN (
SELECT DISTINCT UPPER(type) as object_type
FROM user_source
WHERE name = UPPER(IN_OBJECT))
LOOP
-- set header
setDocHeader(IN_OBJECT, lrec.object_type );
-- get Dependencies
getRefObjects(IN_OBJECT, lrec.object_type);
-- list of privileges
getUnitAllPrivs(IN_OBJECT);
-- trigger source
getUnitSource(IN_OBJECT, lrec.object_type);
ELSIF lrec.object_type IN ('TYPE', 'TYPE BODY')
THEN
IF lrec.object_type = 'TYPE'
THEN
-- attributes
getTypeAttrs(IN_OBJECT);
ELSE
-- type methods
getTypeMethods(IN_OBJECT);
END IF;
-- type source
getUnitSource(IN_OBJECT, lrec.object_type);
ELSE
NULL;
END IF;
END LOOP;
END getPkgDoc;
/* **************************************
Prepare document for Table
* **************************************/
PROCEDURE getTblDoc(
IN_OBJECT VARCHAR2,
IN_OBJECT_TYPE VARCHAR2,
IN_FILE_NAME VARCHAR2)
IS
BEGIN
-- set header
setTblDocHeader(IN_OBJECT, IN_OBJECT_TYPE );
-- get Dependencies
getTblRefObjects(IN_OBJECT, IN_OBJECT_TYPE );
-- columns
getTblCols(IN_OBJECT );
-- constraints
getTblConstraints(IN_OBJECT );
-- indexes
getTblIndexes(IN_OBJECT);
-- privileges
getTblPrivs(IN_OBJECT );
END getTblDoc;
/* **************************************
Main procedure to generate document
* **************************************/
PROCEDURE generateDocInfo(
IN_OBJECT VARCHAR2,
IN_FILE_NAME VARCHAR2,
IN_EMAIL VARCHAR2)
IS
lv_object_type VARCHAR2(255);
BEGIN
-- initialize variables
initDoc(IN_OBJECT);
EXCEPTION
WHEN no_data_found
THEN
DBMS_OUTPUT.PUT_LINE('**************************************************
**********');
DBMS_OUTPUT.PUT_LINE('Object "'||IN_OBJECT||'" not found');
DBMS_OUTPUT.PUT_LINE('**************************************************
**********');
WHEN others
THEN
DBMS_OUTPUT.PUT_LINE('**************************************************
**********');
DBMS_OUTPUT.PUT_LINE( 'ERROR: '||SQLERRM);
DBMS_OUTPUT.PUT_LINE('**************************************************
**********');
END generateDocInfo;
/* **************************************
Main procedure to generate document for all objects for the given
object type
* **************************************/
PROCEDURE generateDocInfoByType(
IN_OBJECT_TYPE VARCHAR2,
IN_FILE_NAME VARCHAR2,
IN_EMAIL VARCHAR2)
IS
ln_check PLS_INTEGER;
BEGIN
-- initialize variables
initDoc(INITCAP(IN_OBJECT_TYPE||'s'));
FOR lrec IN (
SELECT object_name,
object_type
FROM user_objects
WHERE object_type = UPPER(IN_OBJECT_TYPE)
ORDER BY object_name, object_type)
LOOP
IF lrec.object_type IN ('FUNCTION', 'PROCEDURE', 'PACKAGE',
'PACKAGE BODY', 'TRIGGER', 'TYPE' , 'TYPE BODY')
THEN
getPkgDoc(UPPER(lrec.object_name), IN_FILE_NAME);
ELSIF lrec.object_type IN ('TABLE', 'VIEW')
THEN
getTblDoc(UPPER(lrec.object_name), UPPER(lrec.object_type),
IN_FILE_NAME);
ELSE
NULL;
END IF;
END LOOP;
EXCEPTION
WHEN no_data_found
THEN
DBMS_OUTPUT.PUT_LINE('**************************************************
**********');
DBMS_OUTPUT.PUT_LINE('No one object with type "'||
IN_OBJECT_TYPE||'" found');
DBMS_OUTPUT.PUT_LINE('**************************************************
**********');
WHEN others
THEN
DBMS_OUTPUT.PUT_LINE('**************************************************
**********');
DBMS_OUTPUT.PUT_LINE( 'ERROR: '||SQLERRM);
DBMS_OUTPUT.PUT_LINE('**************************************************
**********');
END generateDocInfoByType;
/* **************************************
Main procedure to generate document for all objects for the given
object types
* **************************************/
PROCEDURE generateDocInfoByTypes(
IN_OBJECT_TYPE VARCHAR2,
IN_FILE_NAME VARCHAR2,
IN_EMAIL VARCHAR2)
IS
ln_check PLS_INTEGER;
lb_flag BOOLEAN;
le_unsupportedType EXCEPTION;
BEGIN
-- initialize variables
initDoc(INITCAP(IN_OBJECT_TYPE));
lb_flag := FALSE;
FOR lrec IN (
SELECT object_name,
object_type
FROM user_objects
WHERE object_type = type_index(I)
ORDER BY object_name, object_type)
LOOP
lb_flag := TRUE;
END LOOP;
EXCEPTION
WHEN le_unsupportedType
THEN
DBMS_OUTPUT.PUT_LINE('Type "'||type_index(I)||'" is
unsupported');
WHEN no_data_found
THEN
DBMS_OUTPUT.PUT_LINE('No one object with type "'||
type_index(I)||'" found');
END;
END LOOP;
IF lb_flag
THEN
-- finish documentation: send emails
finishDoc(INITCAP(IN_OBJECT_TYPE), IN_FILE_NAME, IN_EMAIL);
DBMS_OUTPUT.PUT_LINE('**************************************************
**********');
DBMS_OUTPUT.PUT_LINE('Document is generated');
DBMS_OUTPUT.PUT_LINE('**************************************************
**********');
ELSE
DBMS_OUTPUT.PUT_LINE('**************************************************
**********');
DBMS_OUTPUT.PUT_LINE('Document has not been generated');
DBMS_OUTPUT.PUT_LINE('**************************************************
**********');
END IF;
EXCEPTION
WHEN others
THEN
DBMS_OUTPUT.PUT_LINE('**************************************************
**********');
DBMS_OUTPUT.PUT_LINE('ERROR: '||SQLERRM );
DBMS_OUTPUT.PUT_LINE('**************************************************
**********');
END generateDocInfoByTypes;
/* **************************************
Get list of procedures/functions with arguments
* **************************************/
PROCEDURE getArgumentsList(IN_OBJECT VARCHAR2)
IS
lb_function BOOLEAN;
is_args BOOLEAN;
BEGIN
FOR lrec IN (
SELECT DISTINCT
object_name,
DECODE(NVL(overload, -1), -1, 'No', 'Yes') is_overload,
overload
FROM user_arguments
WHERE package_name = IN_OBJECT OR object_name = IN_OBJECT
ORDER BY object_name, overload)
LOOP
lb_function := FALSE;
is_args := TRUE;
FOR lrec_arg IN (
SELECT object_name,
overload,
NVL(argument_name, 'RETURN VALUE') as parameter,
data_type,
in_out,
default_value,
position,
package_name
FROM user_arguments
WHERE NVL(package_name, IN_OBJECT) = IN_OBJECT AND
object_name = lrec.object_name
AND NVL(overload, -1) = NVL(lrec.overload, -1)
ORDER BY object_name, overload, position)
LOOP
IF lb_function = TRUE
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2></FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2></FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2></FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2></FONT></TD>'||CHR(10));
END IF;
-- Type
IF lrec_arg.parameter = 'RETURN VALUE' AND lb_function =
FALSE
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2><B>Function</B></FONT></TD>'||
CHR(10) ), DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2><B>Function</B></FONT></TD>'||
CHR(10));
lb_function := TRUE;
ELSIF lb_function = FALSE
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2><B>Procedure</B></FONT></TD>'||
CHR(10) ), DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2><B>Procedure</B></FONT></TD>'||
CHR(10));
lb_function := TRUE;
ELSE
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2></FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2></FONT></TD>'||CHR(10));
END IF;
-- Parameter
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>'||
lrec_arg.parameter||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec_arg.parameter||'</FONT></TD>'||CHR(10));
-- In/Out
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>'||
lrec_arg.IN_OUT||'</FONT></TD>'||CHR(10) ), DBMS_LOB.GETLENGTH( docBody)
+1, '<TD ALIGN=CENTER VALIGN=top><FONT FACE="ARIAL" SIZE=2>'||
lrec_arg.IN_OUT||'</FONT></TD>'||CHR(10));
-- Datatype
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>'||
lrec_arg.data_type||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec_arg.data_type||'</FONT></TD>'||CHR(10));
END LOOP;
END LOOP;
IF NOT is_args
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END IF;
END getArgumentsList;
/* **************************************
Get trigger columns
* **************************************/
PROCEDURE getTriggerColumns(IN_OBJECT VARCHAR2)
IS
is_cols BOOLEAN;
BEGIN
FOR lrec IN (
SELECT table_owner||'.'||table_name as table_name,
column_name,
column_usage
FROM all_trigger_cols
WHERE trigger_name = IN_OBJECT)
LOOP
is_cols := TRUE;
END LOOP;
IF NOT is_cols
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END IF;
END getTriggerColumns;
/* **************************************
Get trigger details
* **************************************/
PROCEDURE getTriggerDetails(IN_OBJECT VARCHAR2)
IS
is_status BOOLEAN;
BEGIN
is_status := FALSE;
FOR lrec IN (
SELECT base_object_type||' '||table_name as base_object,
status,
trigger_type,
triggering_event,
referencing_names,
when_clause as when_condition
FROM all_triggers
WHERE trigger_name = IN_OBJECT)
LOOP
is_status := TRUE;
END LOOP;
IF NOT is_status
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END IF;
DBMS_LOB.WRITE(docBody, LENGTH( '</TABLE>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TABLE>'||CHR(10));
END getTriggerDetails;
/* **************************************
Get PL/SQL Unit Source
* **************************************/
PROCEDURE getUnitSource(IN_OBJECT VARCHAR2, IN_OBJECT_TYPE VARCHAR2)
IS
BEGIN
END getUnitSource;
/* **************************************
Get type status
* **************************************/
PROCEDURE getTypeStatus(IN_OBJECT VARCHAR2, IN_OBJECT_TYPE VARCHAR2)
IS
is_status BOOLEAN;
BEGIN
is_status := FALSE;
FOR lrec IN (
select a.typecode,
TO_CHAR(a.attributes) AS attributes,
TO_CHAR(a.methods) AS methods,
TO_CHAR(b.created,'MM/DD/YYYY HH24:MI:SS') as created,
TO_CHAR(b.last_ddl_time,'MM/DD/YYYY HH24:MI:SS') as
last_update,
b.status
FROM user_types a,
user_objects b
WHERE type_name = IN_OBJECT
AND b.object_name = a.type_name
AND object_type = IN_OBJECT_TYPE)
LOOP
is_status := TRUE;
END LOOP;
IF NOT is_status
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END IF;
END getTypeStatus;
/* **************************************
Get type attributes
* **************************************/
PROCEDURE getTypeAttrs(IN_OBJECT VARCHAR2)
IS
is_attrs BOOLEAN;
BEGIN
FOR lrec IN (
SELECT attr_name,
attr_type_name,
TO_CHAR(length) AS length,
TO_CHAR(precision) AS precision,
TO_CHAR(scale) AS scale
FROM user_type_attrs
WHERE type_name = IN_OBJECT
ORDER BY attr_no)
LOOP
is_attrs := TRUE;
END LOOP;
IF NOT is_attrs
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END IF;
END getTypeAttrs;
/* **************************************
Get list of type methods
* **************************************/
PROCEDURE getTypeMethods(IN_OBJECT VARCHAR2)
IS
is_methods BOOLEAN;
lb_function BOOLEAN;
BEGIN
FOR lrec IN (
SELECT DISTINCT method_name, method_no
FROM user_method_params
WHERE type_name = IN_OBJECT
ORDER BY method_no)
LOOP
is_methods := TRUE;
lb_function := FALSE;
FOR lrec_arg IN (
SELECT param_name,
param_mode,
param_type_name
FROM user_method_params
WHERE type_name = IN_OBJECT
AND method_name = lrec.method_name
ORDER BY method_no, param_no)
LOOP
IF lb_function = TRUE
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2></FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2></FONT></TD>'||CHR(10));
END IF;
-- Parameter Name
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>'||
lrec_arg.param_name||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec_arg.param_name||'</FONT></TD>'||CHR(10));
-- Param mode
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>'||
lrec_arg.param_mode||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec_arg.param_mode||'</FONT></TD>'||CHR(10));
-- Param Datatype
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>'||
lrec_arg.param_type_name||'</FONT></TD>'||CHR(10) ), DBMS_LOB.GETLENGTH(
docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT FACE="ARIAL" SIZE=2>'||
lrec_arg.param_type_name||'</FONT></TD>'||CHR(10));
END LOOP;
END LOOP;
IF NOT is_methods
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END IF;
END getTypeMethods;
/* **************************************
Get table columns
* **************************************/
PROCEDURE getTblCols(IN_OBJECT VARCHAR2)
IS
BEGIN
FOR lrec IN (
SELECT a.column_name,
DECODE(NVL(a.data_type_owner, '*'), '*', '',
a.data_type_owner||'.')||a.data_type as Data_Type,
a.data_length,
TO_CHAR(a.data_precision) as data_precision,
TO_CHAR(a.data_scale) AS data_scale,
DECODE(a.nullable, 'N', 'No', 'Yes') as nullable,
a.data_default,
b.comments
FROM user_tab_columns a,
user_col_comments b
WHERE a.table_name = IN_OBJECT
AND b.table_name = a.table_name
AND b.column_name = a.column_name
ORDER BY a.column_id)
LOOP
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.column_name||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.column_name||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.Data_Type||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.Data_Type||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.data_length||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.data_length||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.data_precision||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.data_precision||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.data_scale||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.data_scale||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.nullable||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.nullable||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.data_default||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.data_default||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.comments||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.comments||'</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END LOOP;
/* **************************************
Get Table Constraints
* **************************************/
PROCEDURE getTblConstraints(IN_OBJECT VARCHAR2)
IS
is_cons BOOLEAN;
BEGIN
is_cons := FALSE;
FOR lrec IN (
SELECT a.constraint_name,
DECODE( a.constraint_type,
'C', 'Check',
'P', 'Primary key',
'U', 'Unique',
'R', 'Referential',
'V', 'Check option, on a view',
'O', 'Read only, on a view',
'Unknown') AS type,
a.search_condition AS constraint,
a.status,
' ' AS index_name,
b.owner||'.'||b.table_name||' ('||b.constraint_name||')' AS
reference
FROM user_constraints a,
user_constraints b
WHERE a.table_name = IN_OBJECT
AND b.constraint_name(+) = a.r_constraint_name
ORDER BY DECODE( a.constraint_type, 'P', 0, 'U', 1, 'R', 2,
3) )
LOOP
is_cons := TRUE;
IF NOT is_cons
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END IF;
/* **************************************
Get all Table privileges
* **************************************/
PROCEDURE getTblPrivs(IN_OBJECT VARCHAR2)
IS
is_privs BOOLEAN;
-- :1 = IN_OBJECT
-- :2 = IN_GRANTEE
ref_c VARCHAR2(4000) :=
'SELECT
(SELECT DECODE(privilege, ''DELETE'', ''Y'')
FROM all_tab_privs
WHERE table_name = :1
AND grantee = :2
AND privilege = ''DELETE'') del,
(SELECT DECODE(privilege, ''INSERT'', ''Y'')
FROM all_tab_privs
WHERE table_name = :3
AND grantee = :4
AND privilege = ''INSERT'') ins,
(SELECT DECODE(privilege, ''SELECT'', ''Y'')
FROM all_tab_privs
WHERE table_name = :5
AND grantee = :6
AND privilege = ''SELECT'') sel,
(SELECT DECODE(privilege, ''UPDATE'', ''Y'')
FROM all_tab_privs
WHERE table_name = :7
AND grantee = :8
AND privilege = ''UPDATE'') upd
FROM DUAL';
privs_data_del VARCHAR2(30);
privs_data_ins VARCHAR2(30);
privs_data_sel VARCHAR2(30);
privs_data_upd VARCHAR2(30);
BEGIN
FOR lrec IN (
SELECT DISTINCT grantee
FROM all_tab_privs
WHERE table_name = IN_OBJECT)
LOOP
is_privs := TRUE;
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD VALIGN=top><FONT
FACE="ARIAL" SIZE=2>'||lrec.grantee||'</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD VALIGN=top><FONT FACE="ARIAL"
SIZE=2>'||lrec.grantee||'</FONT></TD>'||CHR(10));
IF NOT is_privs
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END IF;
/* **************************************
Get Table Indexes
* **************************************/
PROCEDURE getTblIndexes(IN_OBJECT VARCHAR2)
IS
is_idx BOOLEAN;
TYPE col_type IS TABLE OF user_ind_columns.column_name%TYPE INDEX
BY BINARY_INTEGER;
col_r col_type;
lv_col_names VARCHAR2(500);
BEGIN
is_idx := FALSE;
FOR lrec IN (
SELECT index_name,
index_type,
uniqueness,
status,
TO_CHAR(last_analyzed, 'MM/DD/YYYY HH24:MI:SS') as
last_analyzed
FROM all_indexes
WHERE table_name = IN_OBJECT)
LOOP
is_idx := TRUE;
lv_col_names :='';
FOR I IN col_r.FIRST..col_r.LAST
LOOP
lv_col_names := lv_col_names||col_r(I)||',';
END LOOP;
IF NOT is_idx
THEN
DBMS_LOB.WRITE(docBody, LENGTH( '<TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TR>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '<TD ALIGN=CENTER
VALIGN=top><FONT FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '<TD ALIGN=CENTER VALIGN=top><FONT
FACE="ARIAL" SIZE=2>NOT FOUND</FONT></TD>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</TR>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TR>'||CHR(10));
END IF;
DBMS_LOB.WRITE(docBody, LENGTH( '</TABLE>'||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</TABLE>'||CHR(10));
DBMS_LOB.WRITE(docBody, LENGTH( '</HTML> '||CHR(10) ),
DBMS_LOB.GETLENGTH( docBody)+1, '</HTML> '||CHR(10));
END getTblIndexes;
/* *****************************************
EMAIL
********************************************/
/*
************************************************************************
****
Send email with attachment. Attachment is a CLOB parameter
Parameters
IN_FROM_EMAIL - sender
IN_TO_EMAILS - list of emails separated by ; or ,
IN_CC_EMAILS - list of emails separated by ; or ,
IN_SUBJ - email's Subject
IN_TEXT - email's body
-- CHANGE HISTORY:
12/28/2005 email created
*
************************************************************************
*****/
PROCEDURE sendEmailAttachments(
IN_FROM_EMAIL VARCHAR2,
IN_TO_EMAILS VARCHAR2,
IN_CC_EMAILS VARCHAR2,
IN_SUBJ VARCHAR2,
IN_TEXT CLOB,
IN_MIME_TYPE VARCHAR2 DEFAULT 'text/plain',
IN_FILENAME_1 VARCHAR2,
IN_CONTENT_1 CLOB,
IN_FILENAME_2 VARCHAR2 DEFAULT NULL,
IN_CONTENT_2 CLOB DEFAULT NULL,
IN_FILENAME_3 VARCHAR2 DEFAULT NULL,
IN_CONTENT_3 CLOB DEFAULT NULL)
IS
lv_sender VARCHAR2(2000);
lv_to_email VARCHAR2(2000);
lv_cc_email VARCHAR2(2000);
lv_subj VARCHAR2(500);
lv_msg VARCHAR2(32767);
conn_ UTL_SMTP.CONNECTION;
/* *****************************************
Email
********************************************/
-- set email header and email body
conn_ := setBeginAttachEmail(
IN_FROM_EMAIL,
IN_TO_EMAILS,
IN_CC_EMAILS,
IN_SUBJ,
IN_TEXT,
IN_MIME_TYPE);
-- Attachment Content:
setEmailBody( conn_, IN_CONTENT_1);
-- Attachment Content:
setEmailBody( conn_, IN_CONTENT_2);
-- Attachment Content:
setEmailBody( conn_, IN_CONTENT_3);
-- end attachment
setEndEmail( conn_);
EXCEPTION
WHEN le_params_exception
THEN
RAISE_APPLICATION_ERROR (-20401, 'sendEmail: wrong parameters',
TRUE);
WHEN others
THEN
RAISE;
END sendEmailAttachments;
END documentator;
/
show error