FTP From PL/SQL
Sometimes it's preferable to trigger FTP jobs directly from PL/SQL rather than rely on CRON or AT. This article contains a brief description of the two methods I use.The first method relies on a java stored procedure, described in Shell Commands From PL/SQL, which can be used to trigger a shell script to perform the transfer. The shell script may look like the following:
The second approach uses a combination of the UTL_TCP and UTL_FILE packages to create a simple FTP API ( ftp.pks, ftp.pkb). Once the API is loaded into the appropriate schema simple FTP commands can be initiated as follows:#! /bin/ksh # Move to appropriate directory on local server cd /extracts # FTP all files in directory ftp -inv ftp.company.com <<EOF user ftpuser ftppassword # Move to appropriate directory on remote server. cd /loads ascii mput *.* bye EOF
CREATE OR REPLACE DIRECTORY my_docs AS '/u01/app/oracle/';
SET SERVEROUTPUT ON SIZE 1000000
@c:\ftp.pks
@c:\ftp.pkb
-- Retrieve an ASCII file from a remote FTP server.
DECLARE
l_conn UTL_TCP.connection;
BEGIN
l_conn := ftp.login('ftp.company.com', '21', 'ftpuser', 'ftppassword');
ftp.ascii(p_conn => l_conn);
ftp.get(p_conn => l_conn,
p_from_file => '/u01/app/oracle/test.txt',
p_to_dir => 'MY_DOCS',
p_to_file => 'test_get.txt');
ftp.logout(l_conn);
utl_tcp.close_all_connections;
END;
/
-- Send an ASCII file to a remote FTP server.
DECLARE
l_conn UTL_TCP.connection;
BEGIN
l_conn := ftp.login('ftp.company.com', '21', 'ftpuser', 'ftppassword');
ftp.ascii(p_conn => l_conn);
ftp.put(p_conn => l_conn,
p_from_dir => 'MY_DOCS',
p_from_file => 'test_get.txt',
p_to_file => '/u01/app/oracle/test_put.txt');
ftp.logout(l_conn);
utl_tcp.close_all_connections;
END;
/
-- Retrieve a binary file from a remote FTP server.
DECLARE
l_conn UTL_TCP.connection;
BEGIN
l_conn := ftp.login('ftp.company.com', '21', 'ftpuser', 'ftppassword');
ftp.binary(p_conn => l_conn);
ftp.get(p_conn => l_conn,
p_from_file => '/u01/app/oracle/product/9.2.0.1.0/sysman/reporting/gif/jobs.gif',
p_to_dir => 'MY_DOCS',
p_to_file => 'jobs_get.gif');
ftp.logout(l_conn);
utl_tcp.close_all_connections;
END;
/
-- Send a binary file to a remote FTP server.
DECLARE
l_conn UTL_TCP.connection;
BEGIN
l_conn := ftp.login('ftp.company.com', '21', 'ftpuser', 'ftppassword');
ftp.binary(p_conn => l_conn);
ftp.put(p_conn => l_conn,
p_from_dir => 'MY_DOCS',
p_from_file => 'jobs_get.gif',
p_to_file => '/u01/app/oracle/jobs_put.gif');
ftp.logout(l_conn);
utl_tcp.close_all_connections;
END;
/
-- Get a directory listing from a remote FTP server.
DECLARE
l_conn UTL_TCP.connection;
l_list ftp.t_string_table;
BEGIN
l_conn := ftp.login('ftp.company.com', '21', 'ftpuser', 'ftppassword');
ftp.list(p_conn => l_conn,
p_dir => '/u01/app/oracle',
p_list => l_list);
ftp.logout(l_conn);
utl_tcp.close_all_connections;
IF l_list.COUNT > 0 THEN
FOR i IN l_list.first .. l_list.last LOOP
DBMS_OUTPUT.put_line(i || ': ' || l_list(i));
END LOOP;
END IF;
END;
/
-- Rename a file on a remote FTP server.
DECLARE
l_conn UTL_TCP.connection;
BEGIN
l_conn := ftp.login('ftp.company.com', '21', 'ftpuser', 'ftppassword');
ftp.rename(p_conn => l_conn,
p_from => '/u01/app/oracle/dba/shutdown',
p_to => '/u01/app/oracle/dba/shutdown.old');
ftp.logout(l_conn);
utl_tcp.close_all_connections;
END;
/
-- Delete a file on a remote FTP server.
DECLARE
l_conn UTL_TCP.connection;
BEGIN
l_conn := ftp.login('ftp.company.com', '21', 'ftpuser', 'ftppassword');
ftp.delete(p_conn => l_conn,
p_file => '/u01/app/oracle/dba/temp.txt');
ftp.logout(l_conn);
utl_tcp.close_all_connections;
END;
/
-- Create a directory on a remote FTP server.
DECLARE
l_conn UTL_TCP.connection;
BEGIN
l_conn := ftp.login('ftp.company.com', '21', 'ftpuser', 'ftppassword');
ftp.mkdir(p_conn => l_conn,
p_dir => '/u01/app/oracle/test');
ftp.logout(l_conn);
utl_tcp.close_all_connections;
END;
/
-- Remove a directory from a remote FTP server.
DECLARE
l_conn UTL_TCP.connection;
BEGIN
l_conn := ftp.login('ftp.company.com', '21', 'ftpuser', 'ftppassword');
ftp.rmdir(p_conn => l_conn,
p_dir => '/u01/app/oracle/test');
ftp.logout(l_conn);
utl_tcp.close_all_connections;
END;
/
The basic functions are implemented using LOBs to allow FTP without having to access files on the local filesystem. The get
and put procedures string these together to form a complete job using all the functions. If a straight forward FTP to, or from, the
local filesystem is required it is more efficient to use the GET_DIRECT and PUT_DIRECT procedures as
they avoid the temporary LOBs.The current implementation has the following issues:
- The mput and mget operations are not supported.
- The implementation of binary transfers relies on
UTL_FILEfeatures only available in Oracle9i Release 2. - There is no support for ASCII mode in the
PUT_DIRECTprocedure.
For more information see:
Hope this helps. Regards Tim...
Back to the Top.
