I/O in PL/SQL: Managing Files Displaying Output To Screen Sending Email
I/O in PL/SQL: Managing Files Displaying Output To Screen Sending Email
PL/SQL Obsession
http://www.ToadWorld.com/SF
Download and use any of my scripts (examples, performance scripts, reusable code) from the same location: the demo.zip file.
filename_from_demo_zip.sql
You have my permission to use all these materials to do internal trainings and build your own applications. But remember: they are not production ready. You must test them and modify them to fit your needs.
Copyright 2000-2008 Steven Feuerstein - Page 2
I/O in PL/SQL
You don't always read information from and write data to a relational table. Sometimes you need to read/write files. Sometimes you need to display information to the screen (system output). Sometimes you need to send emails. Sometimes....you need to take advantage of those built-in (supplied) packages.
Copyright 2000-2010 Steven Feuerstein - Page 4
UTL_FILE Logistics
$ORACLE_HOME/Rdbms/Admin
The UTL_FILE package is defined in the utlfile.sql file of the RDBMS/Admin directory.
Ask your DBA for read-only access.
UTL_FILE_DIR
In the bad old days of UTL_FILE, the only way to enable a directory for read/write was the UTL_FILE_DIR parameter.
And after you change it, you have to "bounce" the database before UTL_FILE will recognize the directory.
Very awkward and inflexible. Not well suited for the 24x7 world of the 21st century.
utl_file_dir = /tmp utl_file_dir = /accounts/newdev
Authorizing Directory Access the modern way Now you can take advantage of database directory objects instead of UTL_FILE_DIR.
A directory is a database object, define with a CREATE statement. Once created, it is available for use immediately.
Working with Database Directories The directory hides the actual, hard-coded location.
CREATE OR REPLACE DIRECTORY ERROR_LOG AS '/tmp/apps/log';
Check the ALL_DIRECTORIES view to determine which directories you can use.
SELECT owner, directory_name, directory_path FROM ALL_DIRECTORIES;
create_directories.sql utlfile_92.sql
Opening a File
DECLARE fid UTL_FILE.FILE_TYPE; BEGIN fid := UTL_FILE.FOPEN ('TEMP_DIR', 'test.txt', 'W', max_linesize => 32767); UTL_FILE.fclose (fid); END;
Specify file location, name, operation type and (optionally) the maximum line size. Types are 'R' for Read, 'W' for Write and 'A' for Append. Linesize default is 1024, maximum of 32767 The FOPEN function returns a record ("file handle") based on the UTL_FILE.FILE_TYPE. Contains three fields (ID, datatype and byte_mode). Up to 50 files open per session. fopen.sql
Copyright 2000-2007 Steven Feuerstein - Page 12 fopen_write_conflict.sql
Is a File Open?
DECLARE fid UTL_FILE.file_type; BEGIN fid := UTL_FILE.fopen ('TEMP', 'test.txt', 'W', max_linesize => 32767); IF UTL_FILE.is_open (fid) THEN
Can only read from a file opened with the "R" mode. Can only read one line at a time. The NO_DATA_FOUND exception is raised if you read past the end of the file.
That's more than a little bit silly and a bad idea.
read_from_file.sql infile.sf eqfiles.sf
getnext.sp file_to_collection.sql
Writing to a File
DECLARE fid UTL_FILE.FILE_TYPE; BEGIN fid := UTL_FILE.FOPEN ('TEMP', 'test.txt', 'W'); UTL_FILE.PUT_LINE (fid, 'UTL_FILE'); UTL_FILE.PUT (fid, 'is so much fun'); UTL_FILE.PUTF (fid, ' that I never\nwant to %s', 'stop!'); UTL_FILE.FCLOSE (fid); END;
PUT puts a line without a newline terminator. PUT_LINE = PUT plus newline character. PUTF allows for some formatting and substitution.
\n is new line, %s substitutes strings.
write_to_file.sql display_file.sql create_file.sp read_and_write.sql genaa.sql
You can specify each new line flushed out in call to PUT_LINE. Or call UTL_FILE.FFLUSH to write the accumulated buffer contents out to the file.
put_line_performance.tst Copyright 2000-2010 Steven Feuerstein - Page 17
Closing a File
DECLARE fid UTL_FILE.FILE_TYPE; BEGIN fid := UTL_FILE.FOPEN ('TEMP', 'test.txt', 'R'); UTL_FILE.GET_LINE (fid, myline); UTL_FILE.FCLOSE (fid); EXCEPTION WHEN UTL_FILE.READ_ERROR THEN UTL_FILE.FCLOSE (fid); END;
Very important to close files when you are done with them. And also close them when an exception is raised. Otherwise the file is left open and data will not be flushed out to disk. Close all open files in session with FCLOSE_ALL.
Copyright 2000-2007 Steven Feuerstein - Page 18
Copy a File
DECLARE file_suffix VARCHAR2 (100) := TO_CHAR (SYSDATE, 'YYYYMMDDHH24MISS'); BEGIN UTL_FILE.fcopy ( src_location => 'DEVELOPMENT_DIR', src_filename => 'archive.zip', dest_location => 'ARCHIVE_DIR', dest_filename => 'archive' || file_suffix || '.zip' ); END;
Copy all lines in the file, or a specify range of lines by start and end line numbers. You don't open/close the file.
Copyright 2000-2007 Steven Feuerstein - Page 20
Remove a File
BEGIN UTL_FILE.fremove ( src_location => 'DEVELOPMENT_DIR', src_filename => 'archive.zip' ); EXCEPTION /* Don't forget to check for errors! */ WHEN UTL_FILE.delete_failed THEN ... Deal with failure to remove END;
Rename/move a File
DECLARE file_suffix VARCHAR2 (100) := TO_CHAR (SYSDATE, 'YYYYMMDD'); BEGIN -- Rename/move the entire file in a single step. UTL_FILE.frename ( src_location => 'DEVELOPMENT_DIR', src_filename => 'archive.zip', dest_location => 'ARCHIVE_DIR', dest_filename => 'archive' || file_suffix || '.zip', overwrite => FALSE );END;
Use FRENAME to change the name of a file. If you rename with a new directory, you will move the file.
frename.sql fileIO92.pkg
Copyright 2000-2007 Steven Feuerstein - Page 22
Use the FGETPOS function to get the current relative offset position within a file, in bytes. Returns 0 when you are writing to a file.
fgetpos.sql
Copyright 2000-2010 Steven Feuerstein - Page 23
fgetattr_rec fgetattr_t; BEGIN UTL_FILE.fgetattr ( location => location_in, filename => file_in, fexists => fgetattr_rec.fexists, file_length => fgetattr_rec.file_length, block_size => fgetattr_rec.block_size ); RETURN fgetattr_rec.file_length; END flength;
How big is a file? What is its block size? Does the file exist? All valuable questions. All answered with a call to UTL_FILE.FGETATTR.
flength.sql fileIO92.pkg
external_tables*.*
External Tables 11.2 example: get files in directory In 11.2, Oracle extended the external table concept to include a preprocessor option. You specify an operating system file that will run when you execute a query against the external table.
CREATE TABLE files_in_temp ( file_name VARCHAR2(1000) ) ORGANIZATION external ( TYPE oracle_loader DEFAULT DIRECTORY TEMP ACCESS PARAMETERS ( RECORDS DELIMITED BY NEWLINE PREPROCESSOR execute_directory: 'show_files.bat' FIELDS TERMINATED BY WHITESPACE ) LOCATION ('placeholder.txt') )
Copyright 2000-2010 Steven Feuerstein - Page 28
external_tables_files_in_dir.*
A BFILE is a pointer to an OS file. This will not constitute a training on working with LOBs!
And more...
Read BFILE into LOB Perform INSTR and SUBSTR operations on a BFILE.
Copyright 2000-2010 Steven Feuerstein - Page 30
Initialize BFILE pointer with the BFILENAME function. Then it's all as expected.
bfile_open_close.sql
Use the COMPARE program to find out if two BFILEs are the same.
Specify amount of file you want to compare, and the offset locations in each.
Copyright 2000-2010 Steven Feuerstein - Page 32 bfile_compare.sql
You can also enable output with a call to DBMS_OUTPUT.ENABLE, but it is not enough.
The host environment must also be ready to retrieve the contents of the buffer.
Copyright 2000-2010 Steven Feuerstein - Page 36
dbms_output_demo.sql
Summary: DBMS_OUTPUT
Avoid calls to DBMS_OUTPUT.PUT_LINE in your production code. Do not use this built-in for tracing or debugging. Encapsulate it to make it more useful and less problematic. The demo.zip contains numerous alternatives.
Copyright 2000-2010 Steven Feuerstein - Page 39
Alternatives to DBMS_OUTPUT
The p package
Use "p.l" to say "show me", many overloadings of datatypes.
'[email protected]' '[email protected], [email protected]' '[email protected]' '[email protected]' 'Cool new API for sending email'