Pls_integer vs. number
PLS_INTEGER values require less storage than NUMBER values. Also, PLS_INTEGER operations use machine arithmetic, so they are faster than NUMBER and BINARY_INTEGER operations, which use library arithmetic.Having this, if i add two numbers, one of NUMBER data type and one of pls_integer (or simple_integer) data type, where will this operation be done? In the library arithmetic or machine arithmetic?
What is your Oracle version? Although BINARY_INTEGER has been semi-deprecated since Oracle 7, in 10g it's the same thing as PLS_INTEGER. You might also look up SIMPLE_INTEGER.
Tom's point is that you should be aware of implicit casting, as (for example) SQL statements like SELECT INTO will return the 'fat' NUMBER/INTEGER types and so selecting into a PLS_INTEGER involves a conversion step at runtime, unless the PL/SQL compiler spots it and internally replaces it with a SQL-compatible type anyway (not sure if it does that but I wouldn't be surprised). Also as he mentions, it's not often that the theoretical performance advantages of PLS_INTEGER result in a measurable difference in practice.
However there will often be places in pure PL/SQL code, such as perhaps a counter that you increment, where PLS_INTEGER (or even SIMPLE_INTEGER) is the logical choice even if there is no significant performance advantage.
Also I would always use an integer type (either INTEGER, which is just a constrained NUMBER, or one of the leaner PL/SQL types) if I was dealing with values that should logically be integers, to make it completely clear that there could be no fractional values.
Similar Messages
-
Calling report from form. Need PDF output
I am calling a report from a form using RUN_PRODUCT. I need to display the form in PDF format. When the user clicks the button in the form to run the report, acrobat reader should open up and the report displayed there. Please help.
ThanksThanks for the response. The first part worked. I am able to get the output in PDF format. In the 2nd part where I want to open acrobat and display the output, I am having some trouble with the code. When I compile, it says
win_api_environment.read_registry must be declared. Is there some package I need to attach?
Also, in the After reports trigger, how do I pass vFile (I am assuming this is the PDF file name)?
Thanks
The first thing you'll want to do is pass parameters to the report IE DESTYPE, DESNAME and DESFORMAT where these could be FILE, 'c:\temp\report' and PDF.
Then, you can try this piece of code I wrote (with some help from other people at Metalink and here) sometime back. Now, I call it from forms, but in your case, you'd have to run it in the after report trigger. Since with RUN_PRODUCT you don't know when the report is finished, if you did it from the form, it wouldn't work correctly.
PROCEDURE OPEN_PDF(vFile IN VARCHAR2)
IS
vcServerApp varchar2(40);
vcServerTag varchar2(600);
vcCommand varchar2(2000);
iArgPos pls_integer;
dummy NUMBER;
BEGIN
-- 1 get the Server App for .PDF files
vcServerApp := win_api_environment.read_registry('HKEY_LOCAL_MACHINE\SOFTWARE\CLASSES\.PDF','',true);
-- 2 get the executable
vcServerTag := 'HKEY_LOCAL_MACHINE\SOFTWARE\CLASSES\'||
vcServerApp||'\SHELL\OPEN\COMMAND';
vcCommand:= win_api_environment.read_registry(vcServerTag,'',true);
-- 3 Sort out how to specify the Filename
iArgPos:= instr(vcCommand,'%1');
if iArgPos = 0 then --no substitution Var on the command line
vcCommand := vcCommand||' '||vFile;
else
vcCommand := substr(vcCommand,1,(iArgPos-1))||
vFile||substr(vcCommand,(iArgPos+2));
end if;
-- 4 Run using Winexec (or Host if preferred).
win_api_shell.winexec(vcCommand);
EXCEPTION
when no_data_found then
abortt('Acrobat Reader was not found! Please consult with your help desk to install it and try again.','N');
END;
Chad
I am calling a report from a form using RUN_PRODUCT. I need to display the form in PDF format. When the user clicks the button in the form to run the report, acrobat reader should open up and the report displayed there. Please help.
Thanks -
Convert ORA_FFI to WEBUTIL_C_API to print locally
I am trying to figure out how to convert this package to WEBUTIL_C_API to be able to print to a users local printer (EPSON slip printer)... ANY help would be appreciated...
PACKAGE EPSON_SLIP_PRINTER_INTERFACE IS
* This package provides functions to interact with the EPSON
* TM-U295 slip printers.
* The OPEN_PRINTER function must be called to obtain a printer ID.
* This printer ID can then be used when calling other functions
* that require a printer to be specified.
* NOTE that the printer ID is only valid within the same thread
* that called the OPEN_PRINTER function.
* Brendan Rickey 2004-JAN-09
-- AVAILABLE PRINTERS
CHEQUE_PRINTER VARCHAR2(50) := 'Generic / Text Only droite';
INVOICE_PRINTER VARCHAR2(50) := 'Generic / Text Only left';
-- ERROR CODES
-- Some of the provided functions return a NUMBER value that may hold
-- an error code (negative number).
-- These are the possible error codes:
SUCCESS NUMBER := 0; --no error
ERR_TYPE NUMBER := -10; --parameter type error
ERR_OPENED NUMBER := -20; --printer already opened
ERR_NO_PRINTER NUMBER := -30; --the printer driver does not exist
ERR_NO_TARGET NUMBER := -40; --no printer found (could of off, faulty, unsupported)
ERR_NO_MEMORY NUMBER := -50; --insufficient memory
ERR_HANDLE NUMBER := -60; --invalid printer ID
ERR_TIMEOUT NUMBER := -70; --time out error
ERR_ACCESS NUMBER := -80; --cannot read/write to printer (printing in progress)
ERR_PARAM NUMBER := -90; --parameter error
ERR_OFFLINE NUMBER := -110; --printer was opened in offline state. Status must be changed to online.
ERR_NOT_EPSON NUMBER := -120; --printer is not an EPSON printer
* INITIALIZE
* Initializes the interface between Forms and the EPSON library (call before any other function in the package).
* Returns:
* TRUE if the library is registered successfully,
* FALSE otherwise (library not found etc...)
function INITIALIZE return BOOLEAN;
* OPEN_PRINTER
* Obtains a handle on the specified EPSON slip printer (either CHEQUE_PRINTER or INVOICE_PRINTER).
* Returns:
* a printer ID for the specified printer (greater than 0)
* an error code on failure (less than 0):
* ERR_TYPE, ERR_OPENED, ERR_NO_PRINTER, ERR_NO_TARGET, ERR_NO_MEMORY, ERR_PARAM
function OPEN_PRINTER (p_printer_name IN VARCHAR2) return NUMBER;
* CLOSE_PRINTER
* Releases the handle on the specified printer.
* Returns:
* 0 on success
* ERR_HANDLE on failure
function CLOSE_PRINTER (p_printer_id IN NUMBER) return NUMBER;
* IS_PAPER_OUT
* Tests if there is no paper in the printer.
* Returns:
* 1 if there is no paper in the printer, 0 if paper is in the printer
* ERR_HANDLE or ERR_PARAM on failure.
function IS_PAPER_OUT (p_printer_id IN NUMBER) return NUMBER;
* PRINT_TEXT
* Prints the specified text to the specified printer.
* Returns:
* 0 on success
* ERR_HANDLE, ERR_ACCESS, ERR_OFFLINE, ERR_NOT_EPSON, or ERR_PARAM on failure.
function PRINT_TEXT (p_printer_id IN NUMBER, p_text IN VARCHAR2) return NUMBER;
* RELEASE_PAPER
* Performs the Release function on the specified printer.
* Returns:
* 0 on success
* ERR_HANDLE, ERR_ACCESS, ERR_OFFLINE, ERR_NOT_EPSON, or ERR_PARAM on failure.
function RELEASE_PAPER (p_printer_id IN NUMBER) return NUMBER;
/* PRIVATE FUNCTIONS
function BiOpenMonPrinter(arg0 in PLS_INTEGER,
arg1 in out VARCHAR2)
return PLS_INTEGER;
function BiCloseMonPrinter(arg0 in PLS_INTEGER)
return PLS_INTEGER;
function BiGetStatus(arg0 in PLS_INTEGER,
arg1 in out PLS_INTEGER)
return PLS_INTEGER;
function BiDirectIO(arg0 in PLS_INTEGER,
arg1 in PLS_INTEGER,
arg2 in out VARCHAR2,
arg3 in out PLS_INTEGER,
arg4 in out VARCHAR2,
arg5 in PLS_INTEGER,
arg6 in PLS_INTEGER)
return PLS_INTEGER;
function BiDirectIOEx(arg0 in PLS_INTEGER,
arg1 in PLS_INTEGER,
arg2 in out VARCHAR2,
arg3 in out PLS_INTEGER,
arg4 in out VARCHAR2,
arg5 in PLS_INTEGER,
arg6 in PLS_INTEGER,
arg7 in PLS_INTEGER)
return PLS_INTEGER;
END;
PACKAGE BODY EPSON_SLIP_PRINTER_INTERFACE IS
v_msg_b VARCHAR2(20);
v_EPSON_LIBRARY_OK BOOLEAN:= FALSE;
--ORA_FFI function handles and library handle
lh_EpsStmApi ora_ffi.libHandleType; --DLL library handle
fh_BiOpenMonPrinter ora_ffi.funcHandleType; --DLL function handle
fh_BiCloseMonPrinter ora_ffi.funcHandleType; --DLL function handle
fh_BiGetStatus ora_ffi.funcHandleType; --DLL function handle
fh_BiDirectIO ora_ffi.funcHandleType; --DLL function handle
fh_BiDirectIOEx ora_ffi.funcHandleType; --DLL function handle
--constant
ASB_SLIP_BOF PLS_INTEGER := 4*power(16,5); --BOF printer status flag 0x00400000
c_release_code CHAR(2) := CHR(27)||CHR(113); --ESC+q, to release the paper
-------PRIVATE FUNCTIONS--------
* Brendan Rickey 2004-JAN-09
* The following are functions that are required to interface with the
* EPSON StatusAPI DLL (C library) though ORA_FFI.
* The following describes the DLL functions that are made available
* through this ORA_FFI implementation:
Function Purpose
BiOpenMonPrinter Get a handle on a printer.
Parameters
p_Type --int: 1 if p_Name is a port, 2 if a printer name.
,p_Name --varchar2: the port of printer name to open.
Return printer identifier number (>0) on success, < 0 on failure.
BiCloseMonPrinter Close the monitor on the printer.
Parameters
p_Handle --int: The numerical printer handle returned from BiOpenMonPrinter.
Return 0 on success, < 0 on failure.
BiGetStatus Returns the status of the printer.
Parameters
p_Handle --int: The numerical printer handle returned from BiOpenMonPrinter.
,p_Status OUT --long: The status of the printer (use AND bitwise operator to test for statuses).
Return 0 on success, < 0 on failure.
BiDirectIO Sends data to and Reads data from the printer. Use BiDirectIOEx if more that 255 chars are to be written/read.
Parameters
p_Handle --int: The numerical printer handle returned from BiOpenMonPrinter.
,p_WriteLen --short: The length of the command/data being sent to the printer (max 255).
,p_WriteCmd --varchar2: The command/data to send to the printer.
,p_ReadLen --short: The length of the data to be read from the printer (max 255)
(Use 0 if no data is to be read).
,p_ReadBuff OUT --varchar2: The buffer where the the data read from the printer is stored.
,p_Timeout --long: write/read time out in msecs.
,p_NullTerminate --short: 0 => reading of data from printer is performed until time out or length of p_ReadLen is reached.
1 => reading is finished at thepoint when a NULL is received from the printer. ReadLen must have a value.
Return 0 on success, < 0 on failure.
BiDirectIOEx Sends data to and Reads data from the printer (handles larger quantities of write/read data).
Parameters
p_Handle --int: The numerical printer handle returned from BiOpenMonPrinter.
,p_WriteLen --long: The length of the command/data being sent to the printer.
,p_WriteCmd --varchar2: The command/data to send to the printer.
,p_ReadLen --long: The length of the data to be read from the printer (Use 0 if no data is to be read).
,p_ReadBuff OUT --varchar2: The buffer where the the data read from the printer is stored.
,p_Timeout --long: write/read time out in msecs.
,p_NullTerminate --short: 0 => reading of data from printer is performed until time out or length of p_ReadLen is reached.
1 => reading is finished at thepoint when a NULL is received from the printer. ReadLen must have a value.
,p_Option --short: 0 => prevents Automatic Status Back (ASB) during execution of this function (as does BiDirectIO).
1 => does not disable Automatic Status Back (ASB).
Return 0 on success, < 0 on failure.
function icd_BiOpenMonPrinter(funcHandle in ora_ffi.funcHandleType, arg0 in PLS_INTEGER,
arg1 in out VARCHAR2)
return PLS_INTEGER;
pragma interface(c, icd_BiOpenMonPrinter, 11265);
function BiOpenMonPrinter(arg0 in PLS_INTEGER,
arg1 in out VARCHAR2)
return PLS_INTEGER is
begin
return(icd_BiOpenMonPrinter(fh_BiOpenMonPrinter,
arg0,
arg1));
end;
function icd_BiCloseMonPrinter(funcHandle in ora_ffi.funcHandleType, arg0 in PLS_INTEGER)
return PLS_INTEGER;
pragma interface(c, icd_BiCloseMonPrinter, 11265);
function BiCloseMonPrinter(arg0 in PLS_INTEGER)
return PLS_INTEGER is
begin
return(icd_BiCloseMonPrinter(fh_BiCloseMonPrinter,
arg0));
end;
function icd_BiGetStatus(funcHandle in ora_ffi.funcHandleType, arg0 in PLS_INTEGER,
arg1 in out PLS_INTEGER)
return PLS_INTEGER;
pragma interface(c, icd_BiGetStatus, 11265);
function BiGetStatus(arg0 in PLS_INTEGER,
arg1 in out PLS_INTEGER)
return PLS_INTEGER is
begin
return(icd_BiGetStatus(fh_BiGetStatus,
arg0,
arg1));
end;
function icd_BiDirectIO(funcHandle in ora_ffi.funcHandleType, arg0 in PLS_INTEGER,
arg1 in PLS_INTEGER,
arg2 in out VARCHAR2,
arg3 in out PLS_INTEGER,
arg4 in out VARCHAR2,
arg5 in PLS_INTEGER,
arg6 in PLS_INTEGER)
return PLS_INTEGER;
pragma interface(c, icd_BiDirectIO, 11265);
function BiDirectIO(arg0 in PLS_INTEGER,
arg1 in PLS_INTEGER,
arg2 in out VARCHAR2,
arg3 in out PLS_INTEGER,
arg4 in out VARCHAR2,
arg5 in PLS_INTEGER,
arg6 in PLS_INTEGER)
return PLS_INTEGER is
begin
return(icd_BiDirectIO(fh_BiDirectIO,
arg0,
arg1,
arg2,
arg3,
arg4,
arg5,
arg6));
end;
function icd_BiDirectIOEx(funcHandle in ora_ffi.funcHandleType, arg0 in PLS_INTEGER,
arg1 in PLS_INTEGER,
arg2 in out VARCHAR2,
arg3 in out PLS_INTEGER,
arg4 in out VARCHAR2,
arg5 in PLS_INTEGER,
arg6 in PLS_INTEGER,
arg7 in PLS_INTEGER)
return PLS_INTEGER;
pragma interface(c, icd_BiDirectIOEx, 11265);
function BiDirectIOEx(arg0 in PLS_INTEGER,
arg1 in PLS_INTEGER,
arg2 in out VARCHAR2,
arg3 in out PLS_INTEGER,
arg4 in out VARCHAR2,
arg5 in PLS_INTEGER,
arg6 in PLS_INTEGER,
arg7 in PLS_INTEGER)
return PLS_INTEGER is
begin
return(icd_BiDirectIOEx(fh_BiDirectIOEx,
arg0,
arg1,
arg2,
arg3,
arg4,
arg5,
arg6,
arg7));
end;
--------PUBLIC FUNCTIONS--------
function INITIALIZE return BOOLEAN IS
BEGIN
--When this is the first package function called, code in the package's
--body is executed and sets v_EPSON_LIBRARY_OK.
RETURN v_EPSON_LIBRARY_OK;
END;
function OPEN_PRINTER (p_printer_name IN VARCHAR2) return NUMBER IS
v_printer PLS_INTEGER;
v_printer_name VARCHAR2(50) := p_printer_name;
v_name_type PLS_INTEGER := 2; --use printer Name to specify printer
BEGIN
/* Open a monitor for the printer */
v_printer := BiOpenMonPrinter(v_name_type,v_printer_name);
RETURN v_printer;
END;
function CLOSE_PRINTER (p_printer_id IN NUMBER) return NUMBER IS
v_return PLS_INTEGER;
BEGIN
/* CLOSE the printer monitor */
v_return := BiCloseMonPrinter(p_printer_id);
RETURN v_return;
END;
function IS_PAPER_OUT (p_printer_id IN NUMBER) return NUMBER IS
v_return PLS_INTEGER;
v_status PLS_INTEGER := -123456;
BEGIN
/* Test if paper is in the printer by first getting the status (a binary integer) */
v_return := BiGetStatus(p_printer_id,v_status);
IF v_return <> 0 THEN
RETURN v_return;
ELSE
--Test for BOF status flag
IF WIN_API_BITOP.BITWISE_AND(v_status,ASB_SLIP_BOF) = ASB_SLIP_BOF THEN
RETURN 1; --paper out
ELSE
RETURN 0; --paper in
END IF;
END IF;
END;
function PRINT_TEXT (p_printer_id IN NUMBER, p_text IN VARCHAR2) return NUMBER IS
v_return PLS_INTEGER;
v_text VARCHAR2(2000) := p_text;
v_text_len PLS_INTEGER; --number of characters to be printed
v_read_len PLS_INTEGER := 0; --number of characters to be read from the printer
v_read_buff VARCHAR2(255) := NULL; --not used: holds characters read from the printer
v_timeout PLS_INTEGER := 1000; --not used: amount of time to wait for response (msecs)
v_nullTerm PLS_INTEGER := 0; --not used: 0 means read until reached v_read_len or v_timeout
-- 1 means read until NULL received from printer
v_option PLS_INTEGER := 0; --0 means do not answer other requests while printing
--1 means do not stop answering other requests while printing
BEGIN
--Get the number of chars to be printed and then print.
v_text_len := length(p_text);
v_return := BiDirectIOEx(p_printer_id,
v_text_len,
v_text,
v_read_len,
v_read_buff,
v_timeout,
v_nullTerm,
v_option);
--Ignore timeout(-70) errors, otherwise return error
IF v_return = -70 THEN
v_return := 0;
END IF;
RETURN v_return;
END;
function RELEASE_PAPER (p_printer_id IN NUMBER) return NUMBER IS
BEGIN
/* Release the paper by sending the release escape code to the printer */
RETURN PRINT_TEXT(p_printer_id, c_release_code);
END;
-----END OF FUNCTION IMPLEMENTATIONS-----
BEGIN
* Load the EPSON printer driver's StatusAPI library.
* Create an ORA_FFI interface to the library by doing the following for each desired function:
* 1- Create a handle on the function,
* 2- Register the return value,
* 3- Register the arguments/parameters in the correct order.
lh_EpsStmApi := ora_ffi.load_library('', 'EpsStmApi.DLL');
IF Ora_Ffi.Is_Null_Ptr(lh_EpsStmApi) THEN
AFC_MESSAGES('I','MAIN-0020','E',v_msg_b);
v_EPSON_LIBRARY_OK := FALSE;
ELSE
fh_BiOpenMonPrinter := ora_ffi.register_function(lh_EpsStmApi, 'BiOpenMonPrinter', ora_ffi.c_std);
ora_ffi.register_return(fh_BiOpenMonPrinter, ora_ffi.c_int, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiOpenMonPrinter, ora_ffi.c_int, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiOpenMonPrinter, ora_ffi.c_char_ptr, ora_ffi.pls_varchar2);
fh_BiCloseMonPrinter := ora_ffi.register_function(lh_EpsStmApi, 'BiCloseMonPrinter', ora_ffi.c_std);
ora_ffi.register_return(fh_BiCloseMonPrinter, ora_ffi.c_int, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiCloseMonPrinter, ora_ffi.c_int, ora_ffi.pls_pls_integer);
fh_BiGetStatus := ora_ffi.register_function(lh_EpsStmApi, 'BiGetStatus', ora_ffi.c_std);
ora_ffi.register_return(fh_BiGetStatus, ora_ffi.c_int, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiGetStatus, ora_ffi.c_int, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiGetStatus, ora_ffi.c_long_ptr, ora_ffi.pls_pls_integer);
fh_BiDirectIO := ora_ffi.register_function(lh_EpsStmApi, 'BiDirectIO', ora_ffi.c_std);
ora_ffi.register_return(fh_BiDirectIO, ora_ffi.c_int, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiDirectIO, ora_ffi.c_int, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiDirectIO, ora_ffi.c_short, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiDirectIO, ora_ffi.c_char_ptr, ora_ffi.pls_varchar2);
ora_ffi.register_parameter(fh_BiDirectIO, ora_ffi.c_short_ptr, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiDirectIO, ora_ffi.c_char_ptr, ora_ffi.pls_varchar2);
ora_ffi.register_parameter(fh_BiDirectIO, ora_ffi.c_long, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiDirectIO, ora_ffi.c_short, ora_ffi.pls_pls_integer);
fh_BiDirectIOEx := ora_ffi.register_function(lh_EpsStmApi, 'BiDirectIOEx', ora_ffi.c_std);
ora_ffi.register_return(fh_BiDirectIOEx, ora_ffi.c_int, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiDirectIOEx, ora_ffi.c_int, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiDirectIOEx, ora_ffi.c_long, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiDirectIOEx, ora_ffi.c_char_ptr, ora_ffi.pls_varchar2);
ora_ffi.register_parameter(fh_BiDirectIOEx, ora_ffi.c_long_ptr, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiDirectIOEx, ora_ffi.c_char_ptr, ora_ffi.pls_varchar2);
ora_ffi.register_parameter(fh_BiDirectIOEx, ora_ffi.c_long, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiDirectIOEx, ora_ffi.c_short, ora_ffi.pls_pls_integer);
ora_ffi.register_parameter(fh_BiDirectIOEx, ora_ffi.c_short, ora_ffi.pls_pls_integer);
v_EPSON_LIBRARY_OK := TRUE;
END IF;
EXCEPTION
WHEN OTHERS THEN
AFC_MESSAGES('I','MAIN-0021','E',v_msg_b);
v_EPSON_LIBRARY_OK := FALSE;
END;Hi Duncan,
Thanks for the response. Beyond the problem you pointed out I found that the "open server" command is requiring a window handle parameter, even though it isn't used by the program. I talked with Oracle Support and it turns out that even if the window handle isn't used, it's existence makes it not work with the current version of webutil.
The program I am working with also has a COM interface, so I decided to back up and redo the interface using webutil OLE2. I've got it working now, just a little more polishing to do.
Thanks again for the help.
Mark -
If you need to FTP with PL/SQL...
If you need to perform FTP from within PL/SQL and your database version has the UTL_TCP package, here is a free package you can use. The source code is hopefully documented well enough for you to tell what's going on and how to use the functions. Suggestions on improving the code are welcome, and I can provide limited support via email for what I've written, but I would encourage anyone who uses the code to modify/fix it according to their needs. If you modify the code, I respectfully request that you leave intact the authorship and note comments at the beginning of the package.
Please note that I have not rigorously tested this code, but it has successfully transferred files in both directions in the limited tests that I have performed.
-- Copy the code below and run it in your favorite SQL editor --
CREATE OR REPLACE PACKAGE FTP IS
Simplified FTP client API using UTL_TCP package
Author: Alan Wessman, Brigham Young University
Note: This FTP client attempts to adhere to the protocol and advice found at:
http://cr.yp.to/ftp.html
No warranties are made regarding the correctness of this code.
Notes:
1. Most of these functions will raise UTL_TCP.NETWORK_ERROR if the connection
is not open or is reset during the network transaction. They will also
raise VALUE_ERROR if the server response is ill-formed or a buffer is
too small to hold data. (Most buffers in this package are defined as
VARCHAR2(32767) to avoid size limitations; reduce this if memory overhead
is a concern.)
2. "Verbose mode" can be enabled/disabled by changing the default value of
the vDebug variable in the package body. Setting vDebug to TRUE will
cause a session transcript to be output to DBMS_OUTPUT.
3. The following is an example of how this package might be used:
declare
c utl_tcp.connection;
vresp varchar2(32767);
vbuf varchar2(32767);
vresp_code number;
vremote_host varchar2(32) := 'some.hostname.com';
vusername varchar2(8) := 'username';
vpassword varchar2(8) := 'password';
begin
dbms_output.put_line( 'Opening session...' );
vresp_code := ftp.open_session( c,
vremote_host,
vusername,
vpassword,
vresp,
5 );
vresp_code := ftp.put( c,
'/home/somebody',
'local.test',
'remote.test',
vresp );
vresp_code := ftp.remote_command( c, 'CHMOD 660 remote.test' );
vresp_code := ftp.chdir( c, '/home/somebody/subdir' );
vresp_code := ftp.pwd( c );
vresp_code := ftp.get( c,
'/home/somebody',
'new_file.test',
'another_remote_file.test',
vresp );
vresp_code := ftp.close_session( c );
dbms_output.put_line( 'Closed session.' );
exception
when others then dbms_output.put_line( sqlcode || ':' || sqlerrm );
end;
Function: Open_Session
Description: Begins an FTP session with the remote server.
Parameters:
conn OUT parameter that contains the connection info; to be passed
in to subsequent commands to maintain session state.
host Name or IP address of remote server
username User ID to use for login
password Password to use for login
response OUT parameter; buffer for server replies
timeout_secs Number of seconds for TCP timeout. Pass in NULL to disable
timeout (wait forever for responses). Pass in 0 (zero) for
no wait.
Return value: 0 (zero) if operation is successful; FTP error code if operation
is not successful.
Exceptions: May raise UTL_TCP.NETWORK_ERROR if host parameter is incorrect or if
some other networking error occurs.
May raise VALUE_ERROR if server response is ill-formed.
FUNCTION Open_Session( conn OUT NOCOPY UTL_TCP.Connection,
host IN VARCHAR2,
username IN VARCHAR2,
password IN VARCHAR2,
response OUT VARCHAR2,
timeout_secs IN NUMBER DEFAULT 60 ) RETURN NUMBER;
Function: Get
Description: Retrieves a file on the remote server and stores its contents in
a VARCHAR2 buffer.
Parameters:
conn IN OUT parameter that contains the connection info; to be
passed in to subsequent commands to maintain session state.
buf OUT parameter; buffer for retrieved file contents
remote_path Pathname (including file name) indicating location of remote
file to be retrieved
response OUT parameter; buffer for server replies.
Return value: 0 (zero) if operation is successful; FTP error code if operation
is not successful.
Exceptions: May raise UTL_TCP.NETWORK_ERROR if some networking error occurs.
May raise VALUE_ERROR if server response is ill-formed or buf is
too small for file contents.
FUNCTION Get( conn IN OUT NOCOPY UTL_TCP.Connection,
buf OUT VARCHAR2,
remote_path IN VARCHAR2,
response OUT VARCHAR2 ) RETURN NUMBER;
Function: Get
Description: Retrieves a file on the remote server and stores its contents in
a local file. Assumes an open file handle and does not close it.
Parameters:
conn IN OUT parameter that contains the connection info; to be
passed in to subsequent commands to maintain session state.
local_file IN OUT parameter; UTL_FILE file handle for input file. File
is assumed to be open for writing.
remote_path Pathname (including file name) indicating location of remote
file to be retrieved
response OUT parameter; buffer for server replies.
Return value: 0 (zero) if operation is successful; FTP error code if operation
is not successful.
Exceptions: May raise UTL_TCP.NETWORK_ERROR if some networking error occurs.
May raise VALUE_ERROR if server response is ill-formed or buf is
too small for file contents.
May raise any of the UTL_FILE exceptions if file write operations
fail. See UTL_FILE documentation for additional details.
FUNCTION Get( conn IN OUT NOCOPY UTL_TCP.Connection,
local_file IN OUT UTL_FILE.File_Type,
remote_path IN VARCHAR2,
response OUT VARCHAR2 ) RETURN NUMBER;
Function: Get
Description: Retrieves a file on the remote server and stores its contents in
a local file. Opens and closes local file automatically.
Parameters:
conn IN OUT parameter that contains the connection info; to be
passed in to subsequent commands to maintain session state.
local_path Pathname of local directory in which to store the retrieved
file's contents
local_filename Name of local file in which to store retrieved file's contents
(creates new file or overwrites existing file)
remote_path Pathname (including file name) indicating location of remote
file to be retrieved
response OUT parameter; buffer for server replies.
Return value: 0 (zero) if operation is successful; FTP error code if operation
is not successful.
Exceptions: May raise UTL_TCP.NETWORK_ERROR if some networking error occurs.
May raise VALUE_ERROR if server response is ill-formed or buf is
too small for file contents.
May raise any of the UTL_FILE exceptions if file open, write, or
close operations fail. See UTL_FILE documentation for additional
details.
FUNCTION Get( conn IN OUT NOCOPY UTL_TCP.Connection,
local_path IN VARCHAR2,
local_filename IN VARCHAR2,
remote_path IN VARCHAR2,
response OUT VARCHAR2 ) RETURN NUMBER;
Function: Put
Description: Stores data as a file on the remote server
Parameters:
conn IN OUT parameter that contains the connection info; to be
passed in to subsequent commands to maintain session state.
buf IN parameter; contains data to upload
remote_path Pathname (including file name) indicating location of remote
file to be created/overwritten
response OUT parameter; buffer for server replies.
Return value: 0 (zero) if operation is successful; FTP error code if operation
is not successful.
Exceptions: May raise UTL_TCP.NETWORK_ERROR if some networking error occurs.
May raise VALUE_ERROR if server response is ill-formed.
FUNCTION Put( conn IN OUT NOCOPY UTL_TCP.Connection,
buf IN VARCHAR2,
remote_path IN VARCHAR2,
response OUT VARCHAR2 ) RETURN NUMBER;
Function: Put
Description: Uploads a local file to the remote server. Assumes an open file
handle and does not close it.
Parameters:
conn IN OUT parameter that contains the connection info; to be
passed in to subsequent commands to maintain session state.
local_file IN OUT parameter; UTL_FILE file handle for input file. File
is assumed to be open for reading.
remote_path Pathname (including file name) indicating location of remote
file to be created/overwritten.
response OUT parameter; buffer for server replies.
Return value: 0 (zero) if operation is successful; FTP error code if operation
is not successful.
Exceptions: May raise UTL_TCP.NETWORK_ERROR if some networking error occurs.
May raise VALUE_ERROR if server response is ill-formed.
May raise any of the UTL_FILE exceptions if file read operations
fail. See UTL_FILE documentation for additional details.
FUNCTION Put( conn IN OUT NOCOPY UTL_TCP.Connection,
local_file IN OUT UTL_FILE.File_Type,
remote_path IN VARCHAR2,
response OUT VARCHAR2 ) RETURN NUMBER;
Function: Put
Description: Uploads a local file to the remote server. Opens and closes local
file automatically.
Parameters:
conn IN OUT parameter that contains the connection info; to be
passed in to subsequent commands to maintain session state.
local_path Pathname of local directory in which file to upload exists.
local_filename Name of local file to upload.
remote_path Pathname (including file name) indicating location of remote
file to be created/overwritten.
response OUT parameter; buffer for server replies.
Return value: 0 (zero) if operation is successful; FTP error code if operation
is not successful.
Exceptions: May raise UTL_TCP.NETWORK_ERROR if some networking error occurs.
May raise VALUE_ERROR if server response is ill-formed.
May raise any of the UTL_FILE exceptions if file open, read, or
close operations fail. See UTL_FILE documentation for additional
details.
FUNCTION Put( conn IN OUT NOCOPY UTL_TCP.Connection,
local_path IN VARCHAR2,
local_filename IN VARCHAR2,
remote_path IN VARCHAR2,
response OUT VARCHAR2 ) RETURN NUMBER;
Function: Remote_Command
Description: Sends an arbitrary command to the server via the SITE command.
Parameters:
conn IN OUT parameter that contains the connection info; to be
passed in to subsequent commands to maintain session state.
command Command and parameter(s) to send to the server, e.g.
'CHMOD 600 foo.txt'
Return value: 0 (zero) if operation is successful; FTP error code if operation
is not successful.
Exceptions: May raise UTL_TCP.NETWORK_ERROR if some networking error occurs.
May raise VALUE_ERROR if server response is ill-formed.
FUNCTION Remote_Command( conn IN OUT NOCOPY UTL_TCP.Connection,
command IN VARCHAR2 ) RETURN NUMBER;
Function: Chdir
Description: Changes current working directory on remote server to specified
path.
Parameters:
conn IN OUT parameter that contains the connection info; to be
passed in to subsequent commands to maintain session state.
remote_path Path on remote server to change to.
Return value: 0 (zero) if operation is successful; FTP error code if operation
is not successful.
Exceptions: May raise UTL_TCP.NETWORK_ERROR if some networking error occurs.
May raise VALUE_ERROR if server response is ill-formed.
FUNCTION Chdir( conn IN OUT NOCOPY UTL_TCP.Connection,
remote_path IN VARCHAR2 ) RETURN NUMBER;
Function: Pwd
Description: Prints current working directory (on remote server) to debugging
output if debugging is turned on.
Parameters:
conn IN OUT parameter that contains the connection info; to be
passed in to subsequent commands to maintain session state.
Return value: 0 (zero) if operation is successful; FTP error code if operation
is not successful.
Exceptions: May raise UTL_TCP.NETWORK_ERROR if some networking error occurs.
May raise VALUE_ERROR if server response is ill-formed.
FUNCTION Pwd( conn IN OUT NOCOPY UTL_TCP.Connection ) RETURN NUMBER;
Function: Close_Session
Description: Closes the TCP connection to the remote server.
Parameters:
conn IN OUT parameter that contains the connection info; to be
passed in to subsequent commands to maintain session state.
Return value: 0 (zero)
Exceptions: None raised.
FUNCTION Close_Session( conn IN OUT NOCOPY UTL_TCP.Connection ) RETURN NUMBER;
Function: Close_All_Sessions
Description: Closes all currently open TCP connections.
Parameters: None.
Return value: 0 (zero)
Exceptions: None raised.
FUNCTION Close_All_Sessions RETURN NUMBER;
END FTP;
CREATE OR REPLACE PACKAGE BODY FTP IS
vDebug BOOLEAN := TRUE;
FATAL_ERROR EXCEPTION;
PROCEDURE Debug( msg IN VARCHAR2 ) IS
BEGIN
IF vDebug THEN
DBMS_OUTPUT.Put_Line( msg );
END IF;
END Debug;
FUNCTION Get_Response( conn IN OUT NOCOPY UTL_TCP.Connection,
buf IN OUT VARCHAR2 ) RETURN NUMBER IS
vLen NUMBER;
vCode NUMBER;
vResp VARCHAR2(32767);
BEGIN
vLen := UTL_TCP.READ_LINE( conn, vResp );
Debug( vResp );
-- If TO_NUMBER below fails, let the exception propagate to calling proc
vCode := TO_NUMBER( SUBSTR( vResp, 1, 3 ) );
vResp := SUBSTR( vResp, 4 );
buf := buf || SUBSTR( vResp, 2 );
IF SUBSTR( vResp, 1, 1 ) = '-' THEN
LOOP
vLen := UTL_TCP.READ_LINE( conn, vResp );
Debug( vResp );
<<Get_Code>>
BEGIN
vCode := TO_NUMBER( SUBSTR( vResp, 1, 3 ) );
vResp := SUBSTR( vResp, 4 );
IF SUBSTR( vResp, 1, 1 ) = ' ' THEN
buf := buf || SUBSTR( vResp, 2 );
EXIT;
END IF;
EXCEPTION WHEN VALUE_ERROR THEN NULL;
END Get_Code;
buf := buf || vResp;
END LOOP;
END IF;
RETURN vCode;
END Get_Response;
FUNCTION Do_Command( conn IN OUT NOCOPY UTL_TCP.Connection,
cmd IN VARCHAR2,
response OUT VARCHAR2 ) RETURN NUMBER IS
vResult NUMBER := 0;
BEGIN
vResult := UTL_TCP.WRITE_LINE( conn, cmd );
vResult := Get_Response( conn, response );
RETURN vResult;
END Do_Command;
FUNCTION Parse_Port_Number( port_string IN VARCHAR2 ) RETURN NUMBER IS
vResult NUMBER;
vNew_Port_String VARCHAR2(32767);
BEGIN
-- This stuff parses out the port number encoding from the server reply
-- Reply is in the format xyzh1,h2,h3,h4,p1,p2xyz
-- xyz = possible character data (server-dependent, may not exist)
-- h1-h4 = server IP elements; ignore since we know the host already
-- p1,p2 = port number encoding (port number = p1 * 256 + p2 )
vNew_Port_String := TRANSLATE( port_string, '0123456789', '0000000000' );
vNew_Port_String := SUBSTR( port_string,
INSTR( vNew_Port_String, '0' ),
INSTR( vNew_Port_String, '0', -1 ) -
INSTR( vNew_Port_String, '0' ) + 1 );
vNew_Port_String := SUBSTR( vNew_Port_String,
INSTR( vNew_Port_String, ',', 1, 4 ) + 1 );
vResult := 256 * TO_NUMBER( SUBSTR( vNew_Port_String,
1,
INSTR( vNew_Port_String, ',' ) - 1 ) );
vResult := vResult + TO_NUMBER( SUBSTR( vNew_Port_String,
INSTR( vNew_Port_String, ',' ) + 1 ) );
RETURN vResult;
-- Allow VALUE_ERROR to propagate
END Parse_Port_Number;
FUNCTION Open_Session( conn OUT NOCOPY UTL_TCP.Connection,
host IN VARCHAR2,
username IN VARCHAR2,
password IN VARCHAR2,
response OUT VARCHAR2,
timeout_secs IN NUMBER DEFAULT 60 ) RETURN NUMBER IS
vResp_Code NUMBER;
vGarbage NUMBER; -- For calling functions when we don't care about return val
BEGIN
conn := UTL_TCP.OPEN_CONNECTION( host,
21,
tx_timeout => timeout_secs );
vResp_Code := Get_Response( conn, response );
IF vResp_Code = 220 THEN
vResp_Code := Do_Command( conn, 'USER ' || username, response );
IF vResp_Code IN ( 331, 332 ) THEN
vResp_Code := Do_Command( conn, 'PASS ' || password, response );
IF vResp_Code NOT IN ( 202, 230 ) THEN
RAISE FATAL_ERROR;
END IF;
ELSE
RAISE FATAL_ERROR;
END IF;
END IF;
vResp_Code := Do_Command( conn, 'TYPE I', response );
Debug( 'Logged into ' || conn.remote_host || ' at port ' || conn.remote_port );
RETURN 0;
EXCEPTION
WHEN FATAL_ERROR THEN
Debug( 'Fatal error opening session:' );
Debug( ' Code: ' || vResp_Code );
Debug( ' Response: ' || response );
vGarbage := Close_Session( conn );
RETURN vResp_Code;
END Open_Session;
FUNCTION Get( conn IN OUT NOCOPY UTL_TCP.Connection,
buf OUT VARCHAR2,
remote_path IN VARCHAR2,
response OUT VARCHAR2 ) RETURN NUMBER IS
vResp VARCHAR2(32767);
vResp_Code NUMBER;
vNew_Conn UTL_TCP.Connection;
vNew_Port NUMBER;
BEGIN
-- do PASV
vResp_Code := Do_Command( conn, 'PASV', response );
IF vResp_Code = 227 THEN
<<Switch_Port>>
BEGIN
vNew_Port := Parse_Port_Number( response );
vNew_Conn := UTL_TCP.OPEN_CONNECTION( conn.remote_host,
vNew_Port,
tx_timeout => conn.tx_timeout );
Debug( 'Data connection: ' || vNew_Conn.remote_host || ':' || vNew_Conn.remote_port );
vResp_Code := Do_Command( conn, 'RETR ' || REPLACE( remote_path, CHR(12), CHR(0) ), response );
IF vResp_Code <> 150 THEN
RAISE FATAL_ERROR;
END IF;
<<Get_Download>>
BEGIN
LOOP
vResp := vResp || UTL_TCP.GET_LINE( vNew_Conn, FALSE );
END LOOP;
EXCEPTION
WHEN UTL_TCP.END_OF_INPUT THEN NULL;
END Get_Download;
vResp_Code := Close_Session( vNew_Conn );
vResp_Code := Get_Response( conn, response );
IF vResp_Code BETWEEN 400 AND 599 THEN
RAISE FATAL_ERROR;
END IF;
EXCEPTION
WHEN OTHERS THEN
Debug( SQLERRM );
RAISE FATAL_ERROR;
END Switch_Port;
ELSE
RAISE FATAL_ERROR;
END IF;
vResp_Code := Close_Session( vNew_Conn );
buf := vResp;
RETURN 0;
EXCEPTION
WHEN FATAL_ERROR THEN
Debug( 'Fatal error getting ' || remote_path || ':' );
Debug( ' Code: ' || vResp_Code );
Debug( ' Response: ' || response );
vResp_Code := Close_Session( vNew_Conn );
RETURN vResp_Code;
WHEN OTHERS THEN
Debug( vResp_Code || ': ' || SQLERRM );
RETURN vResp_Code;
END Get;
FUNCTION Get( conn IN OUT NOCOPY UTL_TCP.Connection,
local_file IN OUT UTL_FILE.File_Type,
remote_path IN VARCHAR2,
response OUT VARCHAR2 ) RETURN NUMBER IS
vResp VARCHAR2(32767);
vResp_Code NUMBER := -1;
vNew_Conn UTL_TCP.Connection;
vNew_Port NUMBER;
BEGIN
-- do PASV
vResp_Code := Do_Command( conn, 'PASV', response );
IF vResp_Code = 227 THEN
<<Switch_Port>>
BEGIN
vNew_Port := Parse_Port_Number( response );
vNew_Conn := UTL_TCP.OPEN_CONNECTION( conn.remote_host,
vNew_Port,
tx_timeout => conn.tx_timeout );
Debug( 'Data connection: ' || vNew_Conn.remote_host || ':' || vNew_Conn.remote_port );
vResp_Code := Do_Command( conn, 'RETR ' || REPLACE( remote_path, CHR(12), CHR(0) ), response );
IF vResp_Code <> 150 THEN
RAISE FATAL_ERROR;
END IF;
<<Get_Download>>
BEGIN
LOOP
vResp := UTL_TCP.GET_LINE( vNew_Conn, FALSE );
UTL_FILE.Put( local_file, vResp );
END LOOP;
EXCEPTION
WHEN UTL_TCP.END_OF_INPUT THEN NULL;
END Get_Download;
vResp_Code := Close_Session( vNew_Conn );
vResp_Code := Get_Response( conn, response );
IF vResp_Code BETWEEN 400 AND 599 THEN
RAISE FATAL_ERROR;
END IF;
EXCEPTION
WHEN OTHERS THEN
Debug( SQLERRM );
RAISE FATAL_ERROR;
END Switch_Port;
ELSE
RAISE FATAL_ERROR;
END IF;
vResp_Code := Close_Session( vNew_Conn );
RETURN 0;
EXCEPTION
WHEN FATAL_ERROR THEN
Debug( 'Fatal error getting ' || remote_path || ':' );
Debug( ' Code: ' || vResp_Code );
Debug( ' Response: ' || response );
vResp_Code := Close_Session( vNew_Conn );
RETURN vResp_Code;
WHEN OTHERS THEN
Debug( vResp_Code || ': ' || SQLERRM );
RETURN vResp_Code;
END Get;
FUNCTION Get( conn IN OUT NOCOPY UTL_TCP.Connection,
local_path IN VARCHAR2,
local_filename IN VARCHAR2,
remote_path IN VARCHAR2,
response OUT VARCHAR2 ) RETURN NUMBER IS
vFile UTL_FILE.File_Type;
vResult NUMBER := -1;
BEGIN
vFile := UTL_FILE.FOPEN( local_path, local_filename, 'w' );
vResult := Get( conn, vFile, remote_path, response );
UTL_FILE.FCLOSE( vFile );
RETURN vResult;
EXCEPTION WHEN OTHERS THEN
IF UTL_FILE.IS_OPEN( vFile ) THEN
UTL_FILE.FCLOSE( vFile );
END IF;
RAISE;
END Get;
FUNCTION Put( conn IN OUT NOCOPY UTL_TCP.Connection,
buf IN VARCHAR2,
remote_path IN VARCHAR2,
response OUT VARCHAR2 ) RETURN NUMBER IS
vResp VARCHAR2(32767);
vResp_Code NUMBER;
vNew_Conn UTL_TCP.Connection;
vNew_Port NUMBER;
BEGIN
-- do PASV
vResp_Code := Do_Command( conn, 'PASV', response );
IF vResp_Code = 227 THEN
<<Switch_Port>>
BEGIN
vNew_Port := Parse_Port_Number( response );
vNew_Conn := UTL_TCP.OPEN_CONNECTION( conn.remote_host,
vNew_Port,
tx_timeout => conn.tx_timeout );
Debug( 'Data connection: ' || vNew_Conn.remote_host || ':' || vNew_Conn.remote_port );
vResp_Code := Do_Command( conn, 'STOR ' || REPLACE( remote_path, CHR(12), CHR(0) ), response );
IF vResp_Code <> 150 THEN
RAISE FATAL_ERROR;
END IF;
vResp_Code := UTL_TCP.WRITE_TEXT( vNew_Conn, buf );
UTL_TCP.FLUSH( vNew_Conn );
vResp_Code := Close_Session( vNew_Conn );
vResp_Code := Get_Response( conn, response );
IF vResp_Code BETWEEN 400 AND 599 THEN
RAISE FATAL_ERROR;
END IF;
EXCEPTION
WHEN OTHERS THEN
Debug( SQLERRM );
RAISE FATAL_ERROR;
END Switch_Port;
ELSE
RAISE FATAL_ERROR;
END IF;
vResp_Code := Close_Session( vNew_Conn );
response := vResp;
RETURN 0;
EXCEPTION
WHEN FATAL_ERROR THEN
Debug( 'Fatal error putting ' || remote_path || ':' );
Debug( ' Code: ' || vResp_Code );
Debug( ' Response: ' || response );
vResp_Code := Close_Session( vNew_Conn );
RETURN vResp_Code;
WHEN OTHERS THEN
Debug( vResp_Code || ': ' || SQLERRM );
RETURN vResp_Code;
END Put;
FUNCTION Put( conn IN OUT NOCOPY UTL_TCP.Connection,
local_file IN OUT UTL_FILE.File_Type,
remote_path IN VARCHAR2,
response OUT VARCHAR2 ) RETURN NUMBER IS
vResp VARCHAR2(32767);
vResp_Code NUMBER;
vNew_Conn UTL_TCP.Connection;
vNew_Port NUMBER;
vNew_Port_String VARCHAR2(32767);
BEGIN
-- do PASV
vResp_Code := Do_Command( conn, 'PASV', response );
IF vResp_Code = 227 THEN
<<Switch_Port>>
BEGIN
vNew_Port := Parse_Port_Number( response );
vNew_Conn := UTL_TCP.OPEN_CONNECTION( conn.remote_host,
vNew_Port,
tx_timeout => conn.tx_timeout );
Debug( 'Data connection: ' || vNew_Conn.remote_host || ':' || vNew_Conn.remote_port );
vResp_Code := Do_Command( conn, 'STOR ' || REPLACE( remote_path, CHR(12), CHR(0) ), response );
IF vResp_Code <> 150 THEN
RAISE FATAL_ERROR;
END IF;
<<Get_Download>>
BEGIN
LOOP
UTL_FILE.Get_Line( local_file, vResp );
vResp_Code := UTL_TCP.WRITE_LINE( vNew_Conn, vResp );
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN NULL;
END Get_Download;
vResp_Code := Close_Session( vNew_Conn );
vResp_Code := Get_Response( conn, response );
IF vResp_Code BETWEEN 400 AND 599 THEN
RAISE FATAL_ERROR;
END IF;
EXCEPTION
WHEN OTHERS THEN
Debug( SQLERRM );
RAISE FATAL_ERROR;
END Switch_Port;
ELSE
RAISE FATAL_ERROR;
END IF;
vResp_Code := Close_Session( vNew_Conn );
RETURN 0;
EXCEPTION
WHEN FATAL_ERROR THEN
Debug( 'Fatal error putting ' || remote_path || ':' );
Debug( ' Code: ' || vResp_Code );
Debug( ' Response: ' || response );
vResp_Code := Close_Session( vNew_Conn );
RETURN vResp_Code;
WHEN OTHERS THEN
Debug( vResp_Code || ': ' || SQLERRM );
RETURN vResp_Code;
END Put;
FUNCTION Put( conn IN OUT NOCOPY UTL_TCP.Connection,
local_path IN VARCHAR2,
local_filename IN VARCHAR2,
remote_path IN VARCHAR2,
response OUT VARCHAR2 ) RETURN NUMBER IS
vFile UTL_FILE.File_Type;
vResult NUMBER;
BEGIN
vFile := UTL_FILE.FOPEN( local_path, local_filename, 'r' );
vResult := Put( conn, vFile, remote_path, response );
UTL_FILE.FCLOSE( vFile );
RETURN vResult;
EXCEPTION WHEN OTHERS THEN
IF UTL_FILE.IS_OPEN( vFile ) THEN
UTL_FILE.FCLOSE( vFile );
END IF;
RAISE;
END Put;
FUNCTION Remote_Command( conn IN OUT NOCOPY UTL_TCP.Connection,
command IN VARCHAR2 ) RETURN NUMBER IS
vResp_Code NUMBER;
vResponse VARCHAR2(32767);
BEGIN
vResp_Code := Do_Command( conn, 'SITE ' || command, vResponse );
IF vResp_Code BETWEEN 500 AND 599 THEN
RETURN vResp_Code;
END IF;
RETURN 0;
END Remote_Command;
FUNCTION Chdir( conn IN OUT NOCOPY UTL_TCP.Connection,
remote_path IN VARCHAR2 ) RETURN NUMBER IS
vResp_Code NUMBER;
vResponse VARCHAR2(32767);
BEGIN
vResp_Code := Do_Command( conn, 'CWD ' || REPLACE( remote_path, CHR(12), CHR(0) ), vResponse );
IF vResp_Code BETWEEN 500 AND 599 THEN
RETURN vResp_Code;
END IF;
RETURN 0;
END Chdir;
FUNCTION Pwd( conn IN OUT NOCOPY UTL_TCP.Connection ) RETURN NUMBER IS
vResp_Code NUMBER;
vResponse VARCHAR2(32767);
BEGIN
vResp_Code := Do_Command( conn, 'PWD', vResponse );
IF vResp_Code BETWEEN 500 AND 599 THEN
RETURN vResp_Code;
END IF;
RETURN 0;
END Pwd;
FUNCTION Close_Session( conn IN OUT NOCOPY UTL_TCP.Connection ) RETURN NUMBER IS
BEGIN
IF conn.remote_host IS NULL THEN
RETURN 0;
END IF;
Debug( 'Closing connection on ' || conn.remote_host || ':' || conn.remote_port );
UTL_TCP.Close_Connection( conn );
RETURN 0;
EXCEPTION
WHEN UTL_TCP.NETWORK_ERROR THEN RETURN 0;
END Close_Session;
FUNCTION Close_All_Sessions RETURN NUMBER IS
BEGIN
UTL_TCP.Close_All_Connections;
RETURN 0;
END Close_All_Sessions;
END FTP;Here's another PL/SQL package that will FTP ASCII text files. It assumes that you have proper permissions on the remote host and simply want to transfer one or more text files, not perform any other miscellaneous commands.
Also, from what I have read, in 9i UTL_FILE supports reading and writing of binary data so an FTP client could be written to transfer either ASCII or BINARY files.
Regards,
Russ
CREATE OR REPLACE PACKAGE BRNC_FTP_PKG
AS
* PL/SQL FTP Client
* Created by: Russ Johnson, Braun Consulting
* www.braunconsult.com
* OVERVIEW
* This package uses the standard packages UTL_FILE and UTL_TCP to perform
* client-side FTP functionality (PUT and GET) for text files as defined in
* the World Wide Web Consortium's RFC 959 document - http://www.w3.org/Protocols/rfc959/
* The procedures and functions in this package allow single or multiple file transfer using
* standard TCP/IP connections.
* LIMITATIONS
* Currently the API is limited to transfer of ASCII text files only. This is
* primarily because UTL_FILE only supports text I/O, but also because the original
* design was for creating text files from data in the Oracle database, then transferring the file to a remote host.
* Furthermore, the API does not support SSH/Secure FTP or connection through a proxy server.
* Keep in mind that FTP passes the username/password combo in plain text over TCP/IP.
* DB versions - 8i (8.1.x) and above. 8.0.x may work if it has the SYS.UTL_TCP package.
* Note: Since UTL_FILE is used for the client-side I/O, this package is also limited to
* transfer of files that exist in directories available to UTL_FILE for read/write.
* These directories are defined by the UTL_FILE_DIR parameter in the init.ora file.
* USAGE
* Three functions are available for FTP - PUT, GET, and FTP_MULTIPLE. FTP_MULTIPLE takes
* a table of records that define the files to be transferred (filename, directory, etc.).
* That table can have 1 record or multiple records. The PUT and GET functions are included
* for convenience to FTP one file at a time. PUT and GET return true if the file is transferred
* successfully and false if it fails. FTP_MULTIPLE returns true if no batch-level errors occur
* (such as an invalid host, refused connection, or invalid login information). It also takes the
* table of file records IN and passes it back OUT. Each record contains individual error information.
* EXAMPLE
* Transfer multiple files - 1 GET and 2 PUT from a Windows machine to a host (assuming UNIX here).
* Display any errors that occur.
* DECLARE
* v_username VARCHAR2(40) := 'rjohnson';
* v_password VARCHAR2(40) := 'password';
* v_hostname VARCHAR2(255) := 'ftp.oracle.com';
* v_error_message VARCHAR2(1000);
* b_put BOOLEAN;
* t_files BRNC_FTP_PKG.t_ftp_rec; -- Declare our table of file records
* BEGIN
* t_files(1).localpath := 'd:\oracle\utl_file\outbound';
* t_files(1).filename := 'myfile1.txt';
* t_files(1).remotepath := '/home/oracle/text_files';
* t_files(1).transfer_mode := 'PUT';
* t_files(2).localpath := 'd:\oracle\utl_file\inbound';
* t_files(2).filename := 'incoming_file.xml';
* t_files(2).remotepath := '/home/oracle/xml_files';
* t_files(2).transfer_mode := 'GET';
* t_files(3).localpath := 'd:\oracle\utl_file\outbound';
* t_files(3).filename := 'myfile2.txt';
* t_files(3).remotepath := '/home';
* t_files(3).transfer_mode := 'PUT';
* b_put := BRNC_FTP_PKG.FTP_MULTIPLE(v_error_message,
* t_files,
* v_username,
* v_password,
* v_hostname);
* IF b_put = TRUE
* THEN
* FOR i IN t_files.FIRST..t_files.LAST
* LOOP
* IF t_files.EXISTS(i)
* THEN
* DBMS_OUTPUT.PUT_LINE(t_files(i).status||' | '||
* t_files(i).error_message||' | '||
* to_char(t_files(i).bytes_transmitted)||' | '||
* to_char(t_files(i).trans_start,'YYYY-MM-DD HH:MI:SS')||' | '||
* to_char(t_files(i).trans_end,'YYYY-MM-DD HH:MI:SS'));
* END IF;
* END LOOP;
* ELSE
* DBMS_OUTPUT.PUT_LINE(v_error_message);
* END IF;
* EXCEPTION
* WHEN OTHERS
* THEN
* DBMS_OUTPUT.PUT_LINE(SQLERRM);
* END;
* CREDITS
* The W3C's RFC 959 that describes the FTP process.
* http://www.w3c.org
* Much of the PL/SQL code in this package was based on Java code written by
* Bruce Blackshaw of Enterprise Distributed Technologies Ltd. None of that code
* was copied, but the objects and methods greatly helped my understanding of the
* FTP Client process.
* http://www.enterprisedt.com
* VERSION HISTORY
* 1.0 11/19/2002 Unit-tested single and multiple transfers between disparate hosts.
* Exceptions
ctrl_exception EXCEPTION;
data_exception EXCEPTION;
* Constants - FTP valid response codes
CONNECT_CODE CONSTANT PLS_INTEGER := 220;
USER_CODE CONSTANT PLS_INTEGER := 331;
LOGIN_CODE CONSTANT PLS_INTEGER := 230;
PWD_CODE CONSTANT PLS_INTEGER := 257;
PASV_CODE CONSTANT PLS_INTEGER := 227;
CWD_CODE CONSTANT PLS_INTEGER := 250;
TSFR_START_CODE1 CONSTANT PLS_INTEGER := 125;
TSFR_START_CODE2 CONSTANT PLS_INTEGER := 150;
TSFR_END_CODE CONSTANT PLS_INTEGER := 226;
QUIT_CODE CONSTANT PLS_INTEGER := 221;
SYST_CODE CONSTANT PLS_INTEGER := 215;
TYPE_CODE CONSTANT PLS_INTEGER := 200;
* 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
TYPE r_ftp_rec IS RECORD(localpath VARCHAR2(255),
filename VARCHAR2(255),
remotepath VARCHAR2(255),
filetype VARCHAR2(20),
transfer_mode VARCHAR2(5),
status VARCHAR2(40),
error_message VARCHAR2(255),
bytes_transmitted NUMBER,
trans_start DATE,
trans_end DATE);
* FTP File Table - used to store many files for transfer
TYPE t_ftp_rec IS TABLE of r_ftp_rec INDEX BY BINARY_INTEGER;
* Internal convenience procedure for creating passive host IP address
* and port number.
PROCEDURE CREATE_PASV(p_pasv_cmd IN VARCHAR2,
p_pasv_host OUT VARCHAR2,
p_pasv_port OUT NUMBER);
* Function used to validate FTP server responses based on the
* code passed in p_code. Reads single or multi-line responses.
FUNCTION VALIDATE_REPLY(p_ctrl_con IN OUT UTL_TCP.CONNECTION,
p_code IN PLS_INTEGER,
p_reply OUT VARCHAR2)
RETURN BOOLEAN;
* 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.
FUNCTION VALIDATE_REPLY(p_ctrl_con IN OUT UTL_TCP.CONNECTION,
p_code1 IN PLS_INTEGER,
p_code2 IN PLS_INTEGER,
p_reply OUT VARCHAR2)
RETURN BOOLEAN;
* Procedure that handles the actual data transfer. Meant
* for internal package use. Returns information about the
* actual transfer.
PROCEDURE TRANSFER_ASCII(u_ctrl_con IN OUT UTL_TCP.CONNECTION,
p_localpath IN VARCHAR2,
p_filename IN VARCHAR2,
p_pasv_host IN VARCHAR2,
p_pasv_port IN PLS_INTEGER,
p_transfer_mode IN VARCHAR2,
v_status OUT VARCHAR2,
v_error_message OUT VARCHAR2,
n_bytes_transmitted OUT NUMBER,
d_trans_start OUT DATE,
d_trans_end OUT DATE);
* 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.
FUNCTION FTP_MULTIPLE(p_error_msg OUT VARCHAR2,
p_files IN OUT t_ftp_rec,
p_username IN VARCHAR2,
p_password IN VARCHAR2,
p_hostname IN VARCHAR2,
p_port IN PLS_INTEGER DEFAULT 21)
RETURN BOOLEAN;
* 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
FUNCTION PUT(p_localpath IN VARCHAR2,
p_filename IN VARCHAR2,
p_remotepath IN VARCHAR2,
p_username IN VARCHAR2,
p_password IN VARCHAR2,
p_hostname IN VARCHAR2,
v_status OUT VARCHAR2,
v_error_message OUT VARCHAR2,
n_bytes_transmitted OUT NUMBER,
d_trans_start OUT DATE,
d_trans_end OUT DATE,
p_port IN PLS_INTEGER DEFAULT 21,
p_filetype IN VARCHAR2 := 'ASCII')
RETURN BOOLEAN;
* 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
FUNCTION GET(p_localpath IN VARCHAR2,
p_filename IN VARCHAR2,
p_remotepath IN VARCHAR2,
p_username IN VARCHAR2,
p_password IN VARCHAR2,
p_hostname IN VARCHAR2,
v_status OUT VARCHAR2,
v_error_message OUT VARCHAR2,
n_bytes_transmitted OUT NUMBER,
d_trans_start OUT DATE,
d_trans_end OUT DATE,
p_port IN PLS_INTEGER DEFAULT 21,
p_filetype IN VARCHAR2 := 'ASCII')
RETURN BOOLEAN;
END BRNC_FTP_PKG;
CREATE OR REPLACE PACKAGE BODY BRNC_FTP_PKG
AS
** Create the passive host IP and port number to connect to
PROCEDURE CREATE_PASV(p_pasv_cmd IN VARCHAR2,
p_pasv_host OUT VARCHAR2,
p_pasv_port OUT NUMBER)
IS
v_pasv_cmd VARCHAR2(30) := p_pasv_cmd; --Host and port to connect to for data transfer
n_port_dec NUMBER;
n_port_add NUMBER;
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_cmd)-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
FUNCTION VALIDATE_REPLY(p_ctrl_con IN OUT UTL_TCP.CONNECTION,
p_code IN PLS_INTEGER,
p_reply OUT VARCHAR2)
RETURN BOOLEAN
IS
n_code VARCHAR2(3) := p_code;
n_byte_count PLS_INTEGER;
v_msg VARCHAR2(255);
n_line_count PLS_INTEGER := 0;
BEGIN
LOOP
v_msg := UTL_TCP.GET_LINE(p_ctrl_con);
n_line_count := n_line_count + 1;
IF n_line_count = 1
THEN
p_reply := v_msg;
ELSE
p_reply := p_reply || SUBSTR(v_msg,4);
END IF;
EXIT WHEN INSTR(v_msg,'-',1,1) <> 4;
END LOOP;
IF to_number(SUBSTR(p_reply,1,3)) = n_code
THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
EXCEPTION
WHEN OTHERS
THEN
p_reply := SQLERRM;
RETURN FALSE;
END VALIDATE_REPLY;
** 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
FUNCTION VALIDATE_REPLY(p_ctrl_con IN OUT UTL_TCP.CONNECTION,
p_code1 IN PLS_INTEGER,
p_code2 IN PLS_INTEGER,
p_reply OUT VARCHAR2)
RETURN BOOLEAN
IS
v_code1 VARCHAR2(3) := to_char(p_code1);
v_code2 VARCHAR2(3) := to_char(p_code2);
v_msg VARCHAR2(255);
n_line_count PLS_INTEGER := 0;
BEGIN
LOOP
v_msg := UTL_TCP.GET_LINE(p_ctrl_con);
n_line_count := n_line_count + 1;
IF n_line_count = 1
THEN
p_reply := v_msg;
ELSE
p_reply := p_reply || SUBSTR(v_msg,4);
END IF;
EXIT WHEN INSTR(v_msg,'-',1,1) <> 4;
END LOOP;
IF to_number(SUBSTR(p_reply,1,3)) IN(v_code1,v_code2)
THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
EXCEPTION
WHEN OTHERS
THEN
p_reply := SQLERRM;
RETURN FALSE;
END VALIDATE_REPLY;
** Handles actual data transfer. Responds with status, error message, and
** transfer statistics.
** Potential errors could be with connection or file i/o
PROCEDURE TRANSFER_ASCII(u_ctrl_con IN OUT UTL_TCP.CONNECTION,
p_localpath IN VARCHAR2,
p_filename IN VARCHAR2,
p_pasv_host IN VARCHAR2,
p_pasv_port IN PLS_INTEGER,
p_transfer_mode IN VARCHAR2,
v_status OUT VARCHAR2,
v_error_message OUT VARCHAR2,
n_bytes_transmitted OUT NUMBER,
d_trans_start OUT DATE,
d_trans_end OUT DATE)
IS
u_data_con UTL_TCP.CONNECTION;
u_filehandle UTL_FILE.FILE_TYPE;
v_tsfr_mode VARCHAR2(3) := p_transfer_mode;
v_mode VARCHAR2(1);
v_tsfr_cmd VARCHAR2(10);
v_buffer VARCHAR2(32767);
v_localpath VARCHAR2(255) := p_localpath;
v_filename VARCHAR2(255) := p_filename;
v_host VARCHAR2(20) := p_pasv_host;
n_port PLS_INTEGER := p_pasv_port;
n_bytes NUMBER;
v_msg VARCHAR2(255);
v_reply VARCHAR2(1000);
v_err_status VARCHAR2(20) := 'ERROR';
BEGIN
/** Initialize some of our OUT variables **/
v_status := 'SUCCESS';
v_error_message := ' ';
n_bytes_transmitted := 0;
IF UPPER(v_tsfr_mode) = 'PUT'
THEN
v_mode := 'r';
v_tsfr_cmd := 'STOR ';
ELSIF UPPER(v_tsfr_mode) = 'GET'
THEN
v_mode := 'w';
v_tsfr_cmd := 'RETR ';
END IF;
/** Open data connection on Passive host and port **/
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;
ELSIF UPPER(v_tsfr_mode) = 'GET'
THEN
LOOP
BEGIN
v_buffer := UTL_TCP.GET_LINE(u_data_con,TRUE);
/** Sometimes the TCP/IP buffer sends null data **/
/** we only want to receive the actual data **/
IF v_buffer IS NOT NULL
THEN
UTL_FILE.PUT_LINE(u_filehandle,v_buffer);
n_bytes := LENGTH(v_buffer);
n_bytes_transmitted := n_bytes_transmitted + n_bytes;
END IF;
EXCEPTION
WHEN UTL_TCP.END_OF_INPUT
THEN
EXIT;
END;
END LOOP;
END IF;
/** Flush the buffer on the data connection **/
--UTL_TCP.FLUSH(u_data_con);
d_trans_end := SYSDATE;
/** Close the file **/
UTL_FILE.FCLOSE(u_filehandle);
/** Close the Data Connection **/
UTL_TCP.CLOSE_CONNECTION(u_data_con);
/** Verify the transfer succeeded **/
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.';
ELSIF UPPER(v_tsfr_mode) = 'GET'
THEN
v_error_message := 'The file '||V_filename||' in the directory '||v_localpath||' could not be opened for writing.';
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
FUNCTION FTP_MULTIPLE(p_error_msg OUT VARCHAR2,
p_files IN OUT t_ftp_rec,
p_username IN VARCHAR2,
p_password IN VARCHAR2,
p_hostname IN VARCHAR2,
p_port IN PLS_INTEGER DEFAULT 21)
RETURN BOOLEAN
IS
v_username VARCHAR2(30) := p_username;
v_password VARCHAR2(30) := p_password;
v_hostname VARCHAR2(30) := p_hostname;
n_port PLS_INTEGER := p_port;
u_ctrl_con UTL_TCP.CONNECTION;
n_byte_count PLS_INTEGER;
n_first_index NUMBER;
v_msg VARCHAR2(250);
v_reply VARCHAR2(1000);
v_pasv_host VARCHAR2(20);
n_pasv_port NUMBER;
invalid_transfer EXCEPTION;
BEGIN
p_error_msg := 'FTP Successful'; --Assume the overall transfer will succeed
/** Attempt to connect to the host machine **/
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;
/** Send username **/
n_byte_count := UTL_TCP.WRITE_LINE(u_ctrl_con,'USER '||v_username);
IF VALIDATE_REPLY(u_ctrl_con,USER_CODE,v_reply) = FALSE
THEN
RAISE ctrl_exception;
END IF;
/** Send password **/
n_byte_count := UTL_TCP.WRITE_LINE(u_ctrl_con,'PASS '||v_password);
IF VALIDATE_REPLY(u_ctrl_con,LOGIN_CODE,v_reply) = FALSE
THEN
RAISE ctrl_exception;
END IF;
/** We should be logged in, time to transfer all files **/
FOR i IN p_files.FIRST..p_files.LAST
LOOP
IF p_files.EXISTS(i)
THEN
BEGIN
/** Change to the remotepath directory **/
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;
/** Switch to IMAGE mode **/
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;
/** Get a Passive connection to use for data transfer **/
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);
/** Transfer Data **/
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);
ELSIF UPPER(p_files(i).transfer_mode) = 'GET'
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);
ELSE
RAISE invalid_transfer; -- Raise an exception here
END IF;
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;
/** Send QUIT command **/
n_byte_count := UTL_TCP.WRITE_LINE(u_ctrl_con,'QUIT');
/** 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.
FUNCTION PUT(p_localpath IN VARCHAR2,
p_filename IN VARCHAR2,
p_remotepath IN VARCHAR2,
p_username IN VARCHAR2,
p_password IN VARCHAR2,
p_hostname IN VARCHAR2,
v_status OUT VARCHAR2,
v_error_message OUT VARCHAR2,
n_bytes_transmitted OUT NUMBER,
d_trans_start OUT DATE,
d_trans_end OUT DATE,
p_port IN PLS_INTEGER DEFAULT 21,
p_filetype IN VARCHAR2 := 'ASCII')
RETURN BOOLEAN
IS
t_files t_ftp_rec;
v_username VARCHAR2(30) := p_username;
v_password VARCHAR2(50) := p_password;
v_hostname VARCHAR2(100) := p_hostname;
n_port PLS_INTEGER := p_port;
v_err_msg VARCHAR2(255);
b_ftp BOOLEAN;
BEGIN
t_files(1).localpath := p_localpath;
t_files(1).filename := p_filename;
t_files(1).remotepath := p_remotepath;
t_files(1).filetype := p_filetype;
t_files(1).transfer_mode := 'PUT';
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.
FUNCTION GET(p_localpath IN VARCHAR2,
p_filename IN VARCHAR2,
p_remotepath IN VARCHAR2,
p_username IN VARCHAR2,
p_password IN VARCHAR2,
p_hostname IN VARCHAR2,
v_status OUT VARCHAR2,
v_error_message OUT VARCHAR2,
n_bytes_transmitted OUT NUMBER,
d_trans_start OUT DATE,
d_trans_end OUT DATE,
p_port IN PLS_INTEGER DEFAULT 21,
p_filetype IN VARCHAR2 := 'ASCII')
RETURN BOOLEAN
IS
t_files t_ftp_rec;
v_username VARCHAR2(30) := p_username;
v_password VARCHAR2(50) := p_password;
v_hostname VARCHAR2(100) := p_hostname;
n_port PLS_INTEGER := p_port;
v_err_msg VARCHAR2(255);
b_ftp BOOLEAN;
BEGIN
t_files(1).localpath := p_localpath;
t_files(1).filename := p_filename;
t_files(1).remotepath := p_remotepath;
t_files(1).filetype := p_filetype;
t_files(1).transfer_mode := 'GET';
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 GET;
END BRNC_FTP_PKG;
/ -
ORA-00604 & ORA-30512 CANNOT MODIFY TABLE MORE THAN ONCE IN A TRANSACTION
We have a requirement where two tables should be in sync at any given point
in time with respect to the structure of the tables.
Any change on table/column via ALTER (MODIFY, ADD, RENAME COLUMN, DROP
COLUMN) on the parent table should be replicated to the replica table.
I created a DDL_TRIGGER on the schema and the desired result is achieved but
for the following one scenario for which its failing.
The issue is, if we try to reduce the width of the column (via ALTER ..
MODIFY) it fails with the following error
ORA-00604: error occurred at recursive SQL level 1
ORA-30512: cannot modify DEVTESTF_OIM.REPLICA_ABC more than once in a
transaction
Please follow the steps to reproduce the issue (the issue is across the DB
version checked on 10.2, 11.1 and 11.2 DB version)
-- Step1 Create Parent Table
CREATE TABLE abc (col1 VARCHAR2(10))
-- Step2 Create Replica Table
CREATE TABLE replica_abc (col1 VARCHAR2(10))
-- Step3 Create DDL Trigger
CREATE OR REPLACE TRIGGER ddl_trigger
AFTER ALTER ON SCHEMA
DECLARE
operation VARCHAR2(30);
object_name VARCHAR2(30);
l_sqltext VARCHAR2(100);
i PLS_INTEGER;
l_count NUMBER:=0;
sql_text dbms_standard.ora_name_list_t;
BEGIN
i := dbms_standard.sql_txt(sql_text);
SELECT ora_sysevent, ora_dict_obj_name, UPPER(sql_text(i))
INTO operation, object_name, l_sqltext
FROM dual;
IF ora_dict_obj_name = 'ABC' THEN
l_count := INSTR(l_sqltext,'ADD CONSTRAINT',1,1);
l_count := l_count + INSTR(l_sqltext,'DISABLE',1,1);
l_count := l_count + INSTR(l_sqltext,'DROP CONSTRAINT',1,1);
l_count := l_count + INSTR(l_sqltext,'PRIMARY KEY',1,1);
l_count := l_count + INSTR(l_sqltext,'ADD CHECK',1,1);
IF (l_count = 0) THEN
l_count := INSTR(l_sqltext,'ADD',1,1);
l_count := l_count + INSTR(l_sqltext,'MODIFY',1,1);
l_count := l_count + INSTR(l_sqltext,'DROP COLUMN',1,1);
l_count := l_count + INSTR(l_sqltext,'RENAME
COLUMN',1,1);
IF (l_count >0) THEN
l_sqltext := REPLACE(l_sqltext,'TABLE ABC','TABLE REPLICA_ABC');
execute immediate l_sqltext;
END IF;
END IF;
END IF;
EXCEPTION
WHEN OTHERS THEN
RAISE ;
END;
-- Step 4 Issue the following ALTER command on the Parent table 'ABC'
ALTER TABLE ABC MODIFY COL1 VARCHAR2(9);
will show the following
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-30512: cannot modify DEVTESTF_OIM.REPLICA_ABC more than once in a
transaction
ORA-06512: at line 34
whereas the following commands works fine
ALTER TABLE ABC MODIFY COL1 VARCHAR2(11);
and also the rest of the operations
ALTER TABLE ABC ADD COL2 VARCHAR2(20);
ALTER TABLE ABC RENAME COLUMN COL2 TO COL3;
ALTER TABLE ABC DROP COLUMN COL3;
The issue is while reducing the size of VARCHAR2 columns, while the rest of
option works fine.
Any suggestion or workaround please.It looks like a bug to me. The failing statement from the SQL trace is
PARSE ERROR #12:len=77 dep=3 uid=0 oct=3 lid=0 tim=1263332549608656 err=30512
select /*+ first_rows */ 1 from "TIM"."REPLICA_ABC" where LENGTHB("COL1") > 9and exception cannot explain it. -
Need help in executing report in OIM 10g
Hi,
I am getting error while executing a stored procedure for a report. The error is :
ERROR,10 May 2012 00:25:07,649,[XELLERATE.WEBAPP],Class/Method: ReportAction/displayTabularReport encounter some problems: {1}
Thor.API.Exceptions.tcColumnNotFoundException
at Thor.API.tcMetaDataSet.getColumnType(Unknown Source)
at com.thortech.xl.webclient.util.ReportUtilities.populateTableDataForTabularDisplay(Unknown Source)
at com.thortech.xl.webclient.util.ReportUtilities.displayReportWithTabularLayout(Unknown Source)
at com.thortech.xl.webclient.util.ReportUtilities.displayReportWithLayout(Unknown Source)
at com.thortech.xl.webclient.actions.ReportAction.displayTabularReport(Unknown Source)
at com.thortech.xl.webclient.actions.ReportAction.displayReport(Unknown Source)
at com.thortech.xl.webclient.actions.ReportAction.handleInputParameters(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
for 2 days I am trying to solve this issue by trying different permutation and conbination but its not working. The table takes values from only two tables. Also I tried removing the othertable values and fetch value only from one table but still I am getting above error.
Please help if anybody knows the solution for this.
Thanks,
Kalpana.I created my own report by copying from existing stored procedure. I just changed the select, from & where clause. I am not using any java program. Just changed the stored procedure, created the xml file, saved the parameter mappings in properties file, bounced the server but when I run the report I get this error.
This is the xml file:
<Report layout="tabular">
<StoredProcedure>
<InputParameters>
<InputParameter name="struserlogin_in" order="1" fieldType="TextField" fieldLabel="report.contractorextension.label.reportDateRange" required="true" />
</InputParameters>
</StoredProcedure>
<ReturnColumns>
<ReturnColumn name="Contractor_Id" label="report.contractorextension.label.Contractor_Id" position="Table" order ="1"/>
<ReturnColumn name="Contractor_Name" label="report.contractorextension.label.Contractor_Name" position="Table" order ="2"/>
<ReturnColumn name="Contractor_NTLogon" label="report.contractorextension.label.Contractor_NTLogon" position="Table" order ="3"/>
<ReturnColumn name="USR_STATUS" label="report.contractorextension.label.USR_STATUS" position="Table" order ="4"/>
<ReturnColumn name="USR_END_DATE" label="report.contractorextension.label.USR_END_DATE" position="Table" order ="5"/>
<ReturnColumn name="Supervisor_Name" label="report.contractorextension.label.Supervisor_Name" position="Table" order ="6"/>
<ReturnColumn name="Supervisor_NTLogon" label="report.contractorextension.label.Supervisor_NTLogon" position="Table" order ="7"/>
<ReturnColumn name="Supervsior_EmailId" label="report.contractorextension.label.Supervsior_EmailId" position="Table" order ="8"/>
<ReturnColumn name="Notification_Send_Date" label="report.contractorextension.label.Notification_Send_Date" position="Table" order ="9"/>
<ReturnColumn name="Extension_Date" label="report.contractorextension.label.Extension_Date" position="Table" order ="10"/>
</ReturnColumns>
</Report>
this is the stored procedure:
create or replace
PROCEDURE "XL_SP_CONTRACTOREXTENSION" (
csrresultset_inout IN OUT sys_refcursor,
intuserkey_in IN NUMBER,
strsortcolumn_in IN VARCHAR2,
strsortorder_in IN VARCHAR2,
intstartrow_in IN NUMBER,
intpagesize_in IN NUMBER,
intdocount_in IN NUMBER,
inttotalrows_out OUT NUMBER,
strfiltercolumnlist_in IN VARCHAR2,
strfiltercolumnvaluelist_in IN VARCHAR2,
strudfcolumnlist_in IN VARCHAR2,
strudfcolumnvaluelist_in IN VARCHAR2,
struserlogin_in IN VARCHAR2
AS
BEGIN
Declare
whereclause VARCHAR2(8000);
select_stmt VARCHAR2(8000);
strColumnList VARCHAR2(4000);
strFromClause VARCHAR2(4000);
strWhereClause VARCHAR2(4000);
strOrderByClause VARCHAR2(2000);
intSortDirection_in PLS_INTEGER;
userkey NUMBER(30);
str_row EXCEPTION;
do_cnt EXCEPTION;
no_logged_in_user EXCEPTION;
property_not_found EXCEPTION;
pragma exception_init(Str_row,-20001);
pragma exception_init(Do_cnt,-20002);
pragma exception_init(no_logged_in_user,-20003);
BEGIN
-- Throw exception if the start row or page size is either NULL or have
-- values less than or equal to zero
IF (intstartrow_in <= 0 OR intpagesize_in <= 0 OR intstartrow_in IS NULL
OR intpagesize_in IS NULL) THEN
RAISE str_row;
END IF;
-- Throw exception if the intdocount_in parameter is NULL or has a value
-- other than 0 and 1
IF intdocount_in NOT IN (0, 1, 2) OR intdocount_in IS NULL THEN
RAISE do_cnt;
END IF;
-- Throw exception if the intuserkey_in (logged in user) parameter is NULL
IF intuserkey_in IS NULL or intuserkey_in <= 0 THEN
RAISE no_logged_in_user;
END IF;
-- Now, we start accumulating the whereclause based on the input
-- parameters, performing error checking along the way.
IF struserlogin_in IS NOT NULL THEN
Whereclause :=
whereclause || ' extn.udf_extn_ntlogon IN ( ''' || struserlogin_in || ''')' ;
-- Perform the count query and store the result in inttotalrows_out
-- inttotalrows_out := 0;
IF intdocount_in IN (1,2)
THEN
EXECUTE IMMEDIATE ' SELECT count(*)'
|| ' FROM '
|| ' usr usr,usr usr2 '
|| ' where usr.USR_MANAGER_KEY = usr2.USR_KEY and'
|| ' extn.usr_key= usr.usr_key and '
|| whereclause INTO inttotalrows_out;
-- UI needs the SP to return result set always. The following is returned
-- when the indocount is 2 which does not return any result set but count
IF intdocount_in = 2 THEN
select_stmt := 'SELECT ''dummy'' FROM dual';
OPEN csrresultset_inout FOR select_stmt;
END IF;
END IF;
-- If intdocount_in is 2, UI just wants to get the totalrows to give
-- the warning to users if the result set exceeds the limit set by
-- UI. When ntdocount_in is 2, the following block won't be executed.
-- This is the main query for this stored procedure
If Intdocount_In In (0,1) Then
-- The value of attestation field is NA in case of GTC resource names.
-- If the GTC resource is selected, then "NA" will be displayed in the role name column
Strcolumnlist :='usr.USR_LOGIN AS Contractor_Id, '
--|| 'usr.USR_FIRST_NAME || '' '' || usr.usr_middle_name || '' '' || usr.USR_LAST_NAME AS "Contractor_NTLogon", '
|| 'usr.USR_FIRST_NAME AS Contractor_Name, '
|| 'usr.USR_UDF_NTLOGON AS Contractor_NTLogon,'
|| 'usr.USR_STATUS AS USR_STATUS, '
|| 'usr.USR_END_DATE AS USR_END_DATE, '
--|| 'usr2.usr_first_name || '' '' || usr2.usr_middle_name || '' '' || usr2.usr_last_name AS "Supervisor_Name", '
||'usr2.usr_first_name AS Supervisor_Name, '
|| 'usr2.USR_UDF_NTLOGON AS Supervisor_NTLogon, '
|| 'usr2.USR_EMAIL AS Supervsior_EmailId'
|| 'extn.UDF_EXTN_CREATED AS Notification_Send_Date, '
|| 'extn.UDF_EXTN_EXTENDED AS Extension_Date';
strFromClause :=' ud_co_extn_q extn, usr usr,usr usr2';
strWhereClause := ' usr.USR_MANAGER_KEY = usr2.USR_KEY and '
||' extn.usr_key= usr.usr_key and '
|| whereclause;
IF strsortcolumn_in IS NULL THEN
strOrderByClause := 'extn.UDF_EXTN_EXTENDED';
ELSE
strOrderByClause := strsortcolumn_in;
END IF;
IF strsortorder_in = 'DESC' THEN
intSortDirection_in := 0;
ELSE
intSortDirection_in := 1;
END IF;
XL_SPG_GetPagingSql(strColumnList,
strFromClause,
strWhereClause,
strOrderByClause,
intSortDirection_in,
intStartRow_in,
intPageSize_in,
select_stmt);
OPEN csrresultset_inout FOR select_stmt;
END IF;
END IF;
-- Exception Handling
EXCEPTION
WHEN Str_row THEN
RAISE_APPLICATION_ERROR(sqlcode,
'Start Row/Page Size cannot be NULL OR less than or equal to zero ');
WHEN Do_cnt THEN
RAISE_APPLICATION_ERROR(sqlcode,
'Do Count must be 0, 1 or 2. ');
WHEN no_logged_in_user THEN
RAISE_APPLICATION_ERROR(sqlcode,
'Logged-in User Key cannot be NULL OR less than or equal to zero ');
END;
END XL_SP_CONTRACTOREXTENSION; -
Not able to copy all the record from the table?
Hi All,
I have a table Table_1 with 5 crores of data. I have created the same table structure Table_2 like Table_1 and trying to insert the entire data from Table_1 to Table_2 by use of the below code:
CREATE OR REPLACE PROCEDURE insert_prc (limit_in IN PLS_INTEGER)
IS
cursor cur_insert
IS
SELECT *
FROM Table_1;
type tabtype_insert IS TABLE OF cur_insert%ROWTYPE INDEX BY PLS_INTEGER;
v_tabtype_insert tabtype_insert;
v_limit_rows NUMBER := 1000;
v_start PLS_INTEGER;
v_end PLS_INTEGER;
v_update_count NUMBER;
v_bulk_errors NUMBER;
begin
DBMS_SESSION.free_unused_user_memory;
show_pga_memory (limit_in || ' - BEFORE');
v_start := DBMS_UTILITY.get_cpu_time;
BEGIN
open cur_insert;
LOOP
FETCH cur_insert BULK COLLECT INTO v_tabtype_insert LIMIT v_limit_rows;
FORALL i IN 1..v_tabtype_insert.COUNT SAVE EXCEPTIONS
INSERT INTO Table_2
VALUES v_tabtype_insert(i);
EXIT WHEN v_tabtype_insert.COUNT < v_limit_rows;
COMMIT;
END LOOP;
CLOSE cur_insert;
EXCEPTION
WHEN OTHERS
THEN
v_update_count := 0;
v_bulk_errors := SQL%BULK_EXCEPTIONS.COUNT;
dbms_output.put_line('Number of INSERT statements that failed : ' ||v_bulk_errors);
dbms_output.put_line('*******************************************************************************************************************');
/*FOR i IN 1..v_bulk_errors
LOOP
dbms_output.put_line('An Error ' || i || ' was occured '|| SQL%BULK_EXCEPTIONS(i).ERROR_INDEX ||
' during update of Actuator Model: '|| v_tabtype_mtl_items(SQL%BULK_EXCEPTIONS(i).ERROR_INDEX) ||
' . Oracle error : '|| SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
END LOOP; */
dbms_output.put_line('*******************************************************************************************************************');
END;
v_end := DBMS_UTILITY.get_cpu_time;
DBMS_OUTPUT.put_line ( 'Elapsed CPU time for limit of '
|| limit_in
|| ' = '
|| TO_CHAR (v_end - v_start)/100
show_pga_memory (limit_in || ' - AFTER');
end insert_prc;
CREATE OR REPLACE PROCEDURE APPS.show_pga_memory (
context_in IN VARCHAR2 DEFAULT NULL
SELECT privileges required on:
SYS.v_$session
SYS.v_$sesstat
SYS.v_$statname
Here are the statements you should run:
GRANT SELECT ON SYS.v_$session TO schema;
GRANT SELECT ON SYS.v_$sesstat TO schema;
GRANT SELECT ON SYS.v_$statname TO schema;
IS
l_memory NUMBER;
BEGIN
SELECT st.VALUE
INTO l_memory
FROM SYS.v_$session se, SYS.v_$sesstat st, SYS.v_$statname nm
WHERE se.audsid = USERENV ('SESSIONID')
AND st.statistic# = nm.statistic#
AND se.SID = st.SID
AND nm.NAME = 'session pga memory';
dbms_output.put_line(CASE
WHEN context_in IS NULL
THEN NULL
ELSE context_in || ' - '
END
|| 'PGA memory used in session = '
|| TO_CHAR (l_memory)
END show_pga_memory;
/From the above procedure i am able to insert only some 5000000 data. Remaining 4 crores data is not inserted. But the program says it is completed sucessfully.
Note: Table_2 is the partitioned table and Table_1 is non partitioned table.
Can anyone please what is the problem on above code?
Thanksuser212310 wrote:
-- Using BULK COLLECTS and FORALL's will consume more resources.Ya i will agree that. That's what i am using LIMIT clause passing value as 1000. It means PL/SQL will reuse the same 1000 elements in the collection each time the data is fetched and thus also reuse the same memory. Even if my table grows in size, the PGA consumption will remain stable.Limit or not, your process will consume more resources (and take longer) than the one i showed you. AND it's many many many more lines of code (harder to maintain, etc...).
user212310 wrote:
-- If you don't have a reason (aside from misguided understandings as to which is more performant) to use BULK COLLECTS and FORALL's then you should go with the direct INSERT INTO SELECT * method.The reason i am using BULK COLLECT is to reduce the execution time of the procedure.
Please let me know if i misunderstood something.
ThanksYes, you have.
Please read this
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:760210800346068768 -
What is the "Progid" of Adobe Acrobat reader.
hi,
I am trying to work on OLE invoke the Acrobat Reader File through
ole container, just as to invode and create object for word we are using create_obj('word.application') .
So the 'word.application' is stored in progid of registroy file.
So , i am looking for any file which will be used to invoke pdf file , through ole.
For example :
for word progid is 'word.application'
what is for Adobe Acrobat readerHere's a piece of code I got from someone else a long time ago and modified to open a PDF:
PROCEDURE OPEN_PDF(vFile IN VARCHAR2)
IS
vcServerApp varchar2(40);
vcServerTag varchar2(600);
vcCommand varchar2(2000);
iArgPos pls_integer;
dummy NUMBER;
BEGIN
-- 1 get the Server App for .PDF files
vcServerApp := win_api_environment.read_registry('HKEY_LOCAL_MACHINE\SOFTWARE\CLASSES\.PDF','',true);
-- 2 get the executable
vcServerTag := 'HKEY_LOCAL_MACHINE\SOFTWARE\CLASSES\'||
vcServerApp||'\SHELL\OPEN\COMMAND';
vcCommand:= win_api_environment.read_registry(vcServerTag,'',true);
-- 3 Sort out how to specify the Filename
iArgPos:= instr(vcCommand,'%1');
if iArgPos = 0 then --no substitution Var on the command line
vcCommand := vcCommand||' '||vFile;
else
vcCommand := substr(vcCommand,1,(iArgPos-1))||
vFile||substr(vcCommand,(iArgPos+2));
end if;
-- 4 Run using Winexec (or Host if preferred).
win_api_shell.winexec(vcCommand);
EXCEPTION
when no_data_found then
abortt('Acrobat Reader was not found! Please consult with your help desk to install it and try again.','N');
END; -
Error on "webutil_c_api.invoke_int"
Hello,
i'm testing a DLL that was used in Oracle Forms 6i using ORA_FFI.
the function that i'm testing it on Oracle 10g is :
Function LS100_Open (hwnd in out pls_integer,
Hinst in out pls_integer,
Type_com in char) return pls_integer
The Code in Oracle 10g is :
declare
ret_val pls_integer;
hwnd pls_integer;
handle pls_integer;
typ_com varchar2(1):= 'S';
f_handle webutil_c_api.FunctionHandle;
args webutil_c_api.ParameterList;
param1 webutil_c_api.ParameterHandle;
param2 webutil_c_api.ParameterHandle;
param3 webutil_c_api.ParameterHandle;
begin
f_handle := webutil_c_api.register_function('Ls100.dll','LS100_Open');
args := webutil_c_api.create_parameter_list;
param1 := webutil_c_api.add_parameter(args,webutil_c_api.c_int,webutil_c_api.param_out,hwnd);
param2 := webutil_c_api.add_parameter(args,webutil_c_api.c_int,webutil_c_api.param_out,handle);
param3 := webutil_c_api.add_parameter(args,webutil_c_api.c_char,webutil_c_api.param_in,typ_com,1);
ret_val := webutil_c_api.invoke_int('Ls100.dll','LS100_Open',args);
WEBUTIL_C_API.Destroy_Parameter_List(args);
WEBUTIL_C_API.Deregister_Function(f_handle);
end;
when i execute this code the following error appears:
"WUL-910 Invoking the function failed: java.lang.IllegalArgumentException: unrecognized argument type"
Is there anything wrong in my code ???hi,
the function in dll is:
-- pll in 6i ---
LS100_lhandle ORA_FFI.LIBHANDLETYPE;
LS100_Open_fhandle ORA_FFI.FUNCHANDLETYPE;
FUNCTION ff_LS100_Open (LS100_Open_fhandle ORA_FFI.FUNCHANDLETYPE,
hWnd IN OUT PLS_INTEGER,
Hinst IN OUT PLS_INTEGER,
Type_com IN CHAR) RETURN PLS_INTEGER;
PRAGMA interface (C, ff_LS100_Open, 11265);
FUNCTION LS100_Open (hWnd IN OUT PLS_INTEGER, --not a pointer
Hinst IN OUT PLS_INTEGER, -- not a pointer
Type_com IN CHAR) -- not a pointer
RETURN PLS_INTEGER IS
BEGIN
RETURN( FF_LS100_Open( LS100_Open_fhandle, hWnd, Hinst, Type_com));
END; /* function LS100_Open() */
and in the documentation of the function in the library is defined as :
LS100_Open
#include "LS100.h"
Result API LS100_Open (HWND hwnd,
HANDLE Hinst,
CHAR Type_com);
Description
Open a connection between client and LS service.
Parameters
Hwnd
Handle of the application windows which will receive the notification messages.
Hinst
Hinstance of the application window
Type_com
Execution mode of the command:
SUSPENSIVE_MODE = Synchronous mode
NOT_SUSPENSIVE_MODE = Asynchronous mode
Return Value
LS100_OKAY if successful
LS100_TRY_TO_RESET if the peripheral is in error state otherwise standard reply code.
I have already the howto_ffi.html file and i have already did the following:
- configuring the Webutil 1.0.5 (production release)
- adding the library "LS100" to the Webutil.cfg
- copy the library "LS100" and paste it into webutil\lib
I also tried the following:
I did omit the register/deregister_function, the code become as following and the same error occured after the 3rd add_parameter :
declare
ret_val pls_integer;
hwnd number;
handle number;
typ_com varchar2(1):= 'S';
len_typ pls_integer := 1;
f_handle webutil_c_api.FunctionHandle;
args webutil_c_api.ParameterList;
param1 webutil_c_api.ParameterHandle;
param2 webutil_c_api.ParameterHandle;
param3 webutil_c_api.ParameterHandle;
xx number;
yy number;
begin
-- f_handle := webutil_c_api.register_function('Ls100.dll','LS100_Open');
args := webutil_c_api.create_parameter_list;
message('1');
param1 := webutil_c_api.add_parameter(args,webutil_c_api.c_int,webutil_c_api.param_out,hwnd);
message('2');
param2 := webutil_c_api.add_parameter(args,webutil_c_api.c_int,webutil_c_api.param_out,handle);
message('3');
param3 := webutil_c_api.add_parameter(args,webutil_c_api.c_char,webutil_c_api.param_in,typ_com,len_typ);
Now the same error appears in this stage:
" WUL-910 Invoking the function failed: java.lang.IllegalArgumentException: unrecognized argument type "
and the running continue
message('before invoke_int');
-- the "invoke_int" runs without any errors
ret_val := webutil_c_api.invoke_int('Ls100.dll','LS100_Open',args);
xx := webutil_c_api.get_parameter_number(args,param1);
yy := webutil_c_api.get_parameter_number(args,param2);
message('hwnd ='||xx); -- => 0
message('handle ='||yy); -- => 0
message('ret_val ='||ret_val); -- => <nothing>
WEBUTIL_C_API.Destroy_Parameter_List(args);
--WEBUTIL_C_API.Deregister_Function(f_handle);
end;
Thanks -
Hi all,
I am getting missing keyword error when trying to execute the below function,it doesn't give an error while compiling though.Tried to debug but to vain,can't understand what i am missing.
FUNCTION reprint_file (p_format VARCHAR2,
p_printer_number VARCHAR2,
p_request_id VARCHAR2,
p_order_no_from VARCHAR2 DEFAULT NULL,
p_order_no_to VARCHAR2 DEFAULT NULL,
p_order_date_from VARCHAR2 DEFAULT NULL,
p_order_date_to VARCHAR2 DEFAULT NULL
RETURN VARCHAR2 IS
CURSOR c_format(p_format VARCHAR2) IS
SELECT *
FROM rgl_lookup_data
WHERE format_name = p_format;
TYPE c_ref IS REF CURSOR;
c_rec c_ref;
l_info VARCHAR2(32767);
l_stmt VARCHAR2(6000);
l_order_by VARCHAR2(200):='';
l_exec_stmt VARCHAR2(8000);
l_fp UTL_FILE.FILE_TYPE;
l_filename VARCHAR2(200);
--p_dir_name VARCHAR2(200) := '/usr/tmp';
p_dir_name VARCHAR2(200) := '/d02/oracle/edi/in';
l_order_by_clause VARCHAR2(240);
l_cursor PLS_INTEGER;
l_return NUMBER;
BEGIN
UPDATE rgl_mcy_line_data
SET printer_info = p_printer_number
WHERE header_id = p_request_id;
l_stmt := 'SELECT ''"''||printer_info||''"'''; -- ||''","''||printer_info ';
FOR curr_format IN c_format(p_format)
LOOP
IF curr_format.quantity IS NOT NULL THEN
l_stmt := l_stmt || ' ||'',''||DECODE(quantity, NULL, NULL,''"''||'||'quantity||''"'')';
END IF;
IF curr_format.field_25 IS NOT NULL THEN
l_stmt := l_stmt || ' ||'',''||DECODE(field_25, NULL, NULL,''"''||'||'field_25||''"'')';
END IF;
END LOOP curr_format;
l_exec_stmt := l_stmt
|| ' FROM rgl_lookup_data '
|| ' WHERE format_name = :format_b';
l_filename := 'Reprint_'||'ASP'||'_'||p_request_id||'_'||TO_CHAR(SYSDATE, '_DDMMYYYY_hh24MISS')||'.csv';
l_fp := UTL_FILE.FOPEN(p_dir_name, l_filename, 'w');
OPEN c_rec FOR l_exec_stmt USING p_format;
FETCH c_rec INTO l_info;
CLOSE c_rec;
write_line(l_fp, l_info);
l_exec_stmt := l_stmt
|| ' FROM rgl_mcy_line_data '
|| ' WHERE header_id = :header_id_b '
|| ' AND format = :format_b '
|| ' AND printer_info = :printer_number_b ';
IF p_order_no_from IS NOT NULL AND p_order_no_to IS NOT NULL THEN
l_exec_stmt := l_exec_stmt
|| ' AND order_number BETWEEN :order_no_from_b TO :order_no_from_to ';
ELSIF p_order_no_from IS NOT NULL THEN
l_exec_stmt := l_exec_stmt
|| ' AND order_number >= :order_no_from_b ';
ELSIF p_order_no_to IS NOT NULL THEN
l_exec_stmt := l_exec_stmt
|| ' AND order_number <= :order_no_from_to ';
END IF;
IF p_order_date_from IS NOT NULL AND p_order_date_to IS NOT NULL THEN
l_exec_stmt := l_exec_stmt
|| ' AND order_date BETWEEN :order_date_from_b TO :order_date_from_to ';
ELSIF p_order_date_from IS NOT NULL THEN
l_exec_stmt := l_exec_stmt
|| ' AND order_date >= :order_date_from_b ';
ELSIF p_order_date_to IS NOT NULL THEN
l_exec_stmt := l_exec_stmt
|| ' AND order_date <= :order_date_from_to ';
END IF;
--log_mesg(l_exec_stmt);
dbms_output.put_line('Entered');
l_cursor := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(l_cursor, l_exec_stmt, DBMS_SQL.NATIVE); --Error is showing at this line
DBMS_SQL.DEFINE_COLUMN(l_cursor, 1, l_info, 32767);
DBMS_SQL.BIND_VARIABLE(l_cursor, 'header_id_b', p_request_id);
DBMS_SQL.BIND_VARIABLE(l_cursor, 'format_b', p_format);
DBMS_SQL.BIND_VARIABLE(l_cursor, 'printer_number_b', p_printer_number);
dbms_output.put_line('Exit');
--log_mesg('req:'||p_request_id);
--log_mesg('for:'||p_format);
--log_mesg('pno:'||p_printer_number);
IF p_order_no_from IS NOT NULL THEN
--log_mesg('onf:'||p_order_no_from);
DBMS_SQL.BIND_VARIABLE(l_cursor, 'order_no_from_b', p_order_no_from);
END IF;
IF p_order_no_to IS NOT NULL THEN
--log_mesg('ont:'||p_order_no_to);
DBMS_SQL.BIND_VARIABLE(l_cursor, 'order_no_to_b', p_order_no_to);
END IF;
IF p_order_date_from IS NOT NULL THEN
--log_mesg('odf:'||p_order_date_from);
DBMS_SQL.BIND_VARIABLE(l_cursor, 'order_date_from_b', p_order_date_from);
END IF;
IF p_order_date_to IS NOT NULL THEN
--log_mesg('odt:'||p_order_date_to);
DBMS_SQL.BIND_VARIABLE(l_cursor, 'order_date_to_b', p_order_date_to);
END IF;
l_return := DBMS_SQL.EXECUTE(l_cursor);
LOOP
--log_mesg('inside the loop')
EXIT WHEN DBMS_SQL.FETCH_ROWS(l_cursor) = 0; --curr_rec%NOTFOUND;
DBMS_SQL.COLUMN_VALUE(l_cursor, 1, l_info);
write_line(l_fp, l_info);
END LOOP;
DBMS_SQL.CLOSE_CURSOR(l_cursor);
UTL_FILE.FCLOSE(l_fp);
UPDATE rgl_header_data
SET last_print_date = SYSDATE,
reprint_count = NVL(reprint_count, 0) + 1
WHERE header_id = p_request_id;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
RETURN l_filename;
END rePrint_File;
Function Call
DECLARE
v_result VARCHAR2(1000);
BEGIN
v_result := REGAL_MCY_PRINT_PKG.reprint_file('Macys.lwl','hp4000','6473482927','1213049','1213049',NULL,NULL);
END;
DBMS Messages
Entered
An error was encountered - -905 -ERROR- ORA-00905: missing keyword
Any suggestions,
Thanks in advance!!i didn't find anything wrong with this
DBMS Message before parsing
SELECT '"'||printer_info||'"' ||','||DECODE(quantity, NULL, NULL,'"'||quantity||'"') ||','||DECODE(format, NULL, NULL,'"'||format||'"') ||','||DECODE(duplicates, NULL,NULL,'"'||duplicates||'"') ||','||DECODE(field_1, NULL, NULL,'"'||field_1||'"') ||','||DECODE(field_2, NULL, NULL,'"'||field_2||'"') ||','||DECODE(field_3, NULL, NULL,'"'||field_3||'"') ||','||DECODE(field_4, NULL, NULL,'"'||field_4||'"') ||','||DECODE(field_5, NULL, NULL,'"'||field_5||'"') ||','||DECODE(field_6, NULL, NULL,'"'||field_6||'"') ||','||DECODE(field_7, NULL, NULL,'"'||field_7||'"') ||','||DECODE(field_8, NULL, NULL,'"'||field_8||'"') ||','||DECODE(field_9, NULL, NULL,'"'||field_9||'"') ||','||DECODE(field_10, NULL, NULL,'"'||field_10||'"') ||','||DECODE(field_11, NULL, NULL,'"'||field_11||'"') ||','||DECODE(field_12, NULL, NULL,'"'||field_12||'"') ||','||DECODE(field_13, NULL, NULL,'"'||field_13||'"') ||','||DECODE(field_14, NULL, NULL,'"'||field_14||'"') ||','||DECODE(field_15, NULL, NULL,'"'||field_15||'"') ||','||DECODE(field_16, NULL, NULL,'"'||field_16||'"') ||','||DECODE(field_17, NULL, NULL,'"'||field_17||'"') ||','||DECODE(field_18, NULL, NULL,'"'||field_18||'"') ||','||DECODE(field_19, NULL, NULL,'"'||field_19||'"') ||','||DECODE(field_20, NULL, NULL,'"'||field_20||'"') ||','||DECODE(field_21, NULL, NULL,'"'||field_21||'"') ||','||DECODE(field_22, NULL, NULL,'"'||field_22||'"') ||','||DECODE(field_23, NULL, NULL,'"'||field_23||'"') ||','||DECODE(field_24, NULL, NULL,'"'||field_24||'"') ||','||DECODE(field_25, NULL, NULL,'"'||field_25||'"') FROM rgl_mcy_line_data WHERE header_id = :header_id_b AND format = :format_b AND printer_info = :printer_number_b AND order_number BETWEEN :order_no_from_b TO :order_no_from_to -
Need Help: UTL_FILE Reading and Writing to Text File
Hello I am using version 11gR2 using the UTL_FILE function to read from a text file then write the lines where it begins with word 'foo' and end my writing to the text file where the line with the word 'ZEN' is found. Now, I have several lines that begin with 'foo' and 'ZEN' Which make for one full paragraph, and in this paragraph there's a line that begins with 'DE4.2'. Therefore,
I need to write all paragraphs that include the line 'DE4.2' in their beginning and ending lines 'foo' and 'ZEN'
FOR EXAMPLE:
FOO/234E53LLID
THIS IS MY SECOND LINE
THIS IS MY THIRD LINE
DE4.2 THIS IS MY FOURTH LINE
THIS IS MY FIFTH LINE
ZEN/DING3434343
FOO/234E53LLID
THIS IS MY SECOND LINE
THIS IS MY THIRD LINE
THIS IS MY FIFTH LINE
ZEN/DING3434343
I am only interested in writing the first paragraph tha includes line DE4.2 in one of ther lines Not the Second paragraph that does not include the 'DE4.2'
Here's my code thus far:
CREATE OR REPLACE PROCEDURE my_app2 IS
infile utl_file.file_type;
outfile utl_file.file_type;
buffer VARCHAR2(30000);
b_paragraph_started BOOLEAN := FALSE; -- flag to indicate that required paragraph is started
BEGIN
-- open a file to read
infile := utl_file.fopen('TEST_DIR', 'mytst.txt', 'r');
-- open a file to write
outfile := utl_file.fopen('TEST_DIR', 'out.txt', 'w');
-- check file is opened
IF utl_file.is_open(infile)
THEN
-- loop lines in the file
LOOP
BEGIN
utl_file.get_line(infile, buffer);
--BEGINPOINT APPLICATION
IF buffer LIKE 'foo%' THEN
b_paragraph_started := TRUE;
END IF;
--LOOK FOR GRADS APPS
IF b_paragraph_started AND buffer LIKE '%DE4%' THEN
utl_file.put_line(outfile,buffer, FALSE);
END IF;
--ENDPOINT APPLICATION
IF buffer LIKE 'ZEN%' THEN
b_paragraph_started := FALSE;
END IF;
utl_file.fflush(outfile);
EXCEPTION
WHEN no_data_found THEN
EXIT;
END;
END LOOP;
END IF;
utl_file.fclose(infile);
utl_file.fclose(outfile);
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20099, 'Unknown UTL_FILE Error');
END my_app2;
When I run this code I only get one line: DE4.2 I AM MISSING THE ENTIRE PARAGRAPH
PLEASE ADVISE...Hi,
Look at where you're calling utl_file.put_line. The only time you're writing anything is immediately after you find the the key word 'DE4', and then you're writing just that line.
You need to store the entire paragraph, and when you reach the end of the paragraph, write the whole thing only if you found the key word, like this:
CREATE OR REPLACE PROCEDURE my_app2 IS
TYPE line_collection
IS TABLE OF VARCHAR2 (30000)
INDEX BY BINARY_INTEGER;
infile utl_file.file_type;
outfile utl_file.file_type;
input_paragraph line_collection;
input_paragraph_cnt PLS_INTEGER := 0; -- Number of lines stored in input_paragraph
b_paragraph_started BOOLEAN := FALSE; -- flag to indicate that required paragraph is started
found_key_word BOOLEAN := FALSE; -- Does this paragraph contain the magic word?
BEGIN
-- open a file to read
infile := utl_file.fopen('TEST_DIR', 'mytst.txt', 'r');
-- open a file to write
outfile := utl_file.fopen('TEST_DIR', 'out.txt', 'w');
-- check file is opened
IF utl_file.is_open(infile)
THEN
-- loop lines in the file
LOOP
BEGIN
input_paragraph_cnt := input_paragraph_cnt + 1;
utl_file.get_line (infile, input_paragraph (input_paragraph_cnt));
--BEGINPOINT APPLICATION
IF LOWER (input_paragraph (input_paragraph_cnt)) LIKE 'foo%' THEN
b_paragraph_started := TRUE;
END IF;
--LOOK FOR GRADS APPS
IF b_paragraph_started
THEN
IF input_paragraph (input_paragraph_cnt) LIKE '%DE4%'
THEN
found_key_word := TRUE;
END IF;
--ENDPOINT APPLICATION
IF input_paragraph (input_paragraph_cnt) LIKE 'ZEN%' THEN
b_paragraph_started := FALSE;
IF found_key_word
THEN
FOR j IN 1 .. input_paragraph_cnt
LOOP
utl_file.put_line (outfile, input_paragraph (j), FALSE);
END LOOP;
END IF;
found_key_word := FALSE;
input_paragraph_cnt := 0;
END IF;
ELSE -- paragraph is not started
input_paragraph_cnt := 0;
END IF;
EXCEPTION
WHEN no_data_found THEN
EXIT;
END;
END LOOP;
END IF;
utl_file.fclose (infile);
utl_file.fclose (outfile);
--EXCEPTION
-- WHEN OTHERS THEN
-- raise_application_error(-20099, 'Unknown UTL_FILE Error');
END my_app2;
SHOW ERRORSIf you don't have an EXCEPTION section, the default error handling will print an error message, spcifying exactly what the error was, and which line of your code caused the error. By using your own EXCEPTION section, you're hiding all that information. I admit, the error messages aren't always as informative as we'd like, but they're never less informative than "Unknown UTL_FILE Error'. Don't use your own EXCEPTION handling unless you can improve on the default.
Remember that anything inside quotes is case-sensitive. If your file contains upper-case 'FOO', then it won't be "LIKE 'foo%' ".
Edited by: Frank Kulash on Dec 7, 2011 1:35 PM
You may have noticed that this site normally doesn't display multiple spaces in a row.
Whenever you post formatted text (such as your code) on this site, type these 6 characters:
\{code}
(small letters only, inside curly brackets) before and after each section of formatted text, to preserve spacing. -
Sending PDF as attachment using utl_smtp
Hi all,
I am encountering the following problem when i try to send the email using utl_smtp builtin,i receive the mail in my outlook,but not able to read the contents of the pdf file.
Oracle Version :- Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Prod
source code:-
CREATE OR REPLACE PROCEDURE "PROC_MAIL_ATTACH_PDFS" (
p_cust_nb IN cstm.cstm_cust_nb%TYPE,
from_name IN VARCHAR2,
to_name IN VARCHAR2,
subject IN VARCHAR2,
MESSAGE IN VARCHAR2,
p_binary_file IN VARCHAR2,
p_seq_id IN NUMBER,
p_ret_cd OUT NUMBER,
p_ret_desc OUT VARCHAR2
--ISO-8859-6
IS
v_smtp_server VARCHAR2 (100) := '172.20.204.17';
--change this to your mail server
v_smtp_server_port NUMBER := 25;
v_directory_name VARCHAR2 (100);
v_file_name VARCHAR2 (100);
v_line VARCHAR2 (1000);
crlf VARCHAR2 (2) := CHR (13)
|| CHR (10);
mesg VARCHAR2 (32767);
conn UTL_SMTP.connection;
v_slash_pos NUMBER;
v_file_handle UTL_FILE.file_type;
invalid_path EXCEPTION;
mesg_length_exceeded BOOLEAN := FALSE;
l_msg VARCHAR2 (32000);
l_tag_sep VARCHAR2 (1)
:= func_get_config_value ('TAGSEPRTR');
l_ind VARCHAR2 (10);
l_rec VARCHAR2 (4000);
l_sep_rep VARCHAR2 (4000) := '17_ACCSTMT_NOV_2010';
l_rem_rep VARCHAR2 (4000);
l_rep VARCHAR2 (4000);
l_mim_type VARCHAR2 (2000);
boundary CONSTANT VARCHAR2 (256)
:= '-----DMW.Boundary.605592468';
first_boundary CONSTANT VARCHAR2 (256) := '--' || boundary || crlf;
last_boundary CONSTANT VARCHAR2 (256)
:= '--' || boundary || '--' || crlf;
multipart_mime_type CONSTANT VARCHAR2 (256)
:= 'multipart/mixed; boundary="' || boundary || '"';
mime_type VARCHAR2 (255) := 'text/html';
l_offset NUMBER;
l_ammount NUMBER;
CURSOR cur_trnm
IS
SELECT trnm_email_enarr, trnm_email_anarr
FROM trnm
WHERE trnm_id = 16;
l_enarr trnm.trnm_email_enarr%TYPE;
l_anarr trnm.trnm_email_enarr%TYPE;
l_message_body VARCHAR2 (32000);
--// To check if all mails belongs to the customer already sent...
CURSOR cur_pdfd
IS
SELECT COUNT (*)
FROM pdfd
WHERE pdfd_cust_nb = p_cust_nb
AND pdfd_email_sts IS NULL
--NEWLY ADDED ...
AND NVL (pdfd_stmt_mode, '.') = 'E'
AND TRUNC (pdfd_to_dt) = (SELECT MAX (TRUNC (pdfd_to_dt))
FROM pdfd
WHERE pdfd_cust_nb = p_cust_nb);
l_cnt NUMBER := 0;
PROCEDURE send_header (NAME IN VARCHAR2, header IN VARCHAR2)
IS
BEGIN
UTL_SMTP.write_data (conn, NAME || ': ' || header || crlf);
END;
PROCEDURE write_raw (
p_conn IN OUT NOCOPY UTL_SMTP.connection,
p_message IN RAW
IS
BEGIN
UTL_SMTP.write_raw_data (p_conn, p_message);
END write_raw;
PROCEDURE binary_attachment (
p_conn IN OUT UTL_SMTP.connection,
p_file_name IN VARCHAR2,
p_mime_type IN VARCHAR2
IS
k_max_line_width CONSTANT PLS_INTEGER DEFAULT 54;
v_amt BINARY_INTEGER := 672 * 3;
/* ensures proper format; 2016 */
v_bfile BFILE;
v_file_len PLS_INTEGER;
v_buf RAW (2100);
v_buf1 RAW (2100);
v_modulo PLS_INTEGER;
v_pieces PLS_INTEGER;
v_file_pos PLS_INTEGER := 1;
v_data RAW (32767);
v_data1 RAW (32767);
v_chunks PLS_INTEGER;
l_amt NUMBER := 32767;
l_off NUMBER := 1;
l_raw RAW (32767);
l_raw1 RAW (32767);
l_lob BLOB;
l_lob_empt BLOB;
req UTL_HTTP.req;
resp UTL_HTTP.resp;
resp_empt UTL_HTTP.resp;
l_url VARCHAR2 (4000);
l_rep_path VARCHAR2 (2000);
l_report VARCHAR2 (100);
l_seq_nb repq.repq_seq_nb%TYPE;
l_parm repq.repq_parm_val%TYPE;
l_repq repq%ROWTYPE;
l_sts NUMBER;
l_user VARCHAR2 (10);
--L_MSG VARCHAR2(32000);
l_seq_id NUMBER;
usr_err EXCEPTION;
--// 07-Jun-2009 - Basheer A.S. : Code added for sending A/c Statement and PFL statements in single e-mail ...
CURSOR cur_pdfd
IS
SELECT
--UTL_COMPRESS.LZ_UNCOMPRESS(PDFD_DB_FILE) PDFD_DB_FILE,
pdfd_file_name
FROM pdfd
WHERE pdfd_cust_nb = p_cust_nb
--AND PDFD_EMAIL_STS IS NULL
--NEWLY ADDED ...
--AND NVL(PDFD_STMT_MODE,'.') = 'E'
AND pdfd_seq_nb = p_seq_id
AND TRUNC (pdfd_to_dt) = (SELECT MAX (TRUNC (pdfd_to_dt))
FROM pdfd
WHERE pdfd_cust_nb = p_cust_nb);
l_buffer_size INTEGER := 57;
l_offset INTEGER := 1;
l_raw RAW (57);
l_file_nm pdfd.pdfd_file_name%TYPE;
BEGIN
--// 06-Jun-2009 - Basheer A.S. : Code added for sending A/c Statement and PFL statements in a single e-mail ...
--// Initializing temporary CLOB data ...
DBMS_LOB.createtemporary (l_lob, FALSE);
--DBMS_LOB.createtemporary(L_LOB_EMPT, FALSE);
--// Loop thro all the records for the given Customer Number...
OPEN cur_pdfd;
LOOP
--FETCH CUR_PDFD INTO L_LOB, L_FILE_NM;
FETCH cur_pdfd
INTO --L_LOB_EMPT,
l_file_nm;
EXIT WHEN cur_pdfd%NOTFOUND;
proc_audit_log ('T',
'PROC_MAIL_ATTACH_PDFS, Customer No. '
|| p_cust_nb
|| ', File attachment: '
|| l_file_nm
UTL_SMTP.write_data (conn, first_boundary);
UTL_SMTP.write_data (conn,
'Content-Transfer-Encoding: base64 '
|| UTL_TCP.crlf
UTL_SMTP.write_data (conn,
'Content-Type: ' || mime_type || UTL_TCP.crlf
UTL_SMTP.write_data (conn,
'Content-Disposition: ATTACHMENT; filename="'
|| p_file_name
|| '"'
|| UTL_TCP.crlf
UTL_SMTP.write_data (conn, crlf);
l_ind := '1.1';
v_file_pos := 1;
--// Attaching individual PDF files ...
BEGIN
v_modulo := 0;
v_pieces := 0;
v_amt := 2016;
l_ind := '2.1';
v_file_len := DBMS_LOB.getlength (l_lob);
--v_file_len := dbms_lob.getlength(L_LOB_EMPT);
v_modulo := MOD (v_file_len, v_amt);
v_pieces := TRUNC (v_file_len / v_amt);
IF (v_modulo <> 0)
THEN
v_pieces := v_pieces + 1;
END IF;
l_ind := '2.2';
DBMS_LOB.READ (l_lob, v_amt, v_file_pos, v_buf);
--dbms_lob.read(L_LOB_EMPT, v_amt, v_file_pos, v_buf);
v_data := v_data1;
v_chunks := 0;
v_data := v_data1;
FOR i IN 1 .. v_pieces
LOOP
v_file_pos := i * v_amt + 1;
v_file_len := v_file_len - v_amt;
v_data := UTL_RAW.CONCAT (v_data, v_buf);
l_ind := '2.3';
v_chunks := TRUNC (UTL_RAW.LENGTH (v_data) / k_max_line_width);
IF (i <> v_pieces)
THEN
v_chunks := v_chunks - 1;
END IF;
l_ind := '2.4';
write_raw (p_conn => p_conn,
p_message => UTL_ENCODE.base64_encode (v_data)
v_data := v_data1;
IF (v_file_len < v_amt AND v_file_len > 0)
THEN
v_amt := v_file_len;
END IF;
l_ind := '2.5';
DBMS_LOB.READ (l_lob, v_amt, v_file_pos, v_buf);
--DBMS_LOB.READ(L_LOB_EMPT, v_amt, v_file_pos, v_buf);
END LOOP;
EXCEPTION
WHEN OTHERS
THEN
proc_audit_log
('E',
'PROC_MAIL_ATTACH_PDFS.binary_attachment.inside BLOB loop, :'
|| SQLERRM
|| ',ind:'
|| l_ind
END;
v_file_pos := 1;
UTL_SMTP.write_data (conn, UTL_TCP.crlf);
UTL_SMTP.write_data (conn, UTL_TCP.crlf);
END LOOP;
--// END multiple file attachments
l_ind := '2.6';
UTL_SMTP.write_data (p_conn, last_boundary || UTL_TCP.crlf);
EXCEPTION
WHEN OTHERS
THEN
proc_audit_log ('E',
'PROC_MAIL_ATTACH_PDFS, when others:'
|| l_ind
|| ', '
|| SQLERRM
END binary_attachment;
BEGIN
--// If no pending emails for the given Customer, then exit the process...
OPEN cur_pdfd;
FETCH cur_pdfd
INTO l_cnt;
CLOSE cur_pdfd;
--// If still pending statements needs to be send...
--IF L_CNT > 0 THEN
IF l_cnt = 0
THEN
OPEN cur_trnm;
FETCH cur_trnm
INTO l_enarr, l_anarr;
CLOSE cur_trnm;
l_message_body :=
'<html>'
||
--'<meta http-equiv="Content-Type" content="text/html; charset=WINDOWS-1256(Arabic)">'||
--'<meta http-equiv="Content-Type" content="text/html; charset=WINDOWS-1256">'||
'<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-6">'
|| '<body>
<TABLE BORDER="0" WIDTH=100% style="table-layout:fixed;">
<TR>
<TD WIDTH="50%" ALIGN="LEFT" style="word-wrap: break-word"><B>'
|| l_enarr
|| '</B></TD>'
|| '<TD WIDTH="50%" ALIGN="RIGHT" style="word-wrap: break-word"><B>'
|| l_anarr
|| '</B></TD></TR></TABLE>
</body>
</html>';
proc_audit_log ('T', 'PROC_MAIL_ATTACH_PDFS, msg:' || l_msg);
v_smtp_server := func_get_config_value ('MAILHOST');
v_smtp_server_port := func_get_config_value ('MAILPORT');
l_ind := '3.1';
conn := UTL_SMTP.open_connection (v_smtp_server, v_smtp_server_port);
--utl_smtp.helo( conn, v_smtp_server );
--utl_smtp.mail( conn, '[email protected]' );
UTL_SMTP.helo (conn, v_smtp_server);
UTL_SMTP.mail (conn, from_name);
UTL_SMTP.rcpt (conn, to_name);
l_ind := '3.2';
l_rec := func_eti_tagval (l_msg, 'EMAIL');
proc_audit_log ('T', 'PROC_MAIL_ATTACH_PDFS, l_rec:' || l_rec);
proc_audit_log ('T', 'l_sep_rep1' || l_sep_rep);
UTL_SMTP.open_data (conn);
send_header ('From', '<' || from_name || '>');
send_header ('To', '<' || to_name || '>');
--send_header('To',''||Func_Eti_Tagval(L_MSG, 'EMAIL')||'');
send_header ('Date', TO_CHAR (SYSDATE, 'dd Mon yy hh24:mi:ss'));
send_header ('Subject', subject);
send_header ('Content-Type', multipart_mime_type);
UTL_SMTP.write_data (conn, first_boundary);
--utl_smtp.write_data(conn, 'Content-Type: '||mime_type||utl_tcp.crlf);
--utl_smtp.write_data(conn, 'Content-Type: '||mime_type||'; charset=Windows-1256'||utl_tcp.crlf);
UTL_SMTP.write_data (conn,
'Content-Type: '
|| mime_type
|| '; charset=ISO-8859-6'
|| UTL_TCP.crlf
--new...
UTL_SMTP.write_data (conn, crlf);
UTL_SMTP.write_raw_data (conn, UTL_RAW.cast_to_raw (l_message_body));
UTL_SMTP.write_data (conn, crlf);
UTL_SMTP.write_data (conn, crlf);
proc_audit_log ('T', 'l_sep_rep2' || l_sep_rep);
binary_attachment (p_conn => conn,
p_file_name => l_sep_rep || '.pdf',
p_mime_type => 'multipart/mixed'
); --||l_sep_rep||'.pdf');
UTL_SMTP.write_data (conn, last_boundary || UTL_TCP.crlf);
UTL_SMTP.close_data (conn);
UTL_SMTP.quit (conn);
END IF;
p_ret_cd := 0;
p_ret_desc := 'Mail sent successfully';
EXCEPTION
WHEN OTHERS
THEN
proc_audit_log ('E',
'PROC_MAIL_ATTACH_PDFS, error:'
|| SQLERRM
|| 'ind:'
|| l_ind
p_ret_cd := 1;
END;
Kindly help me to resolve this issue.
Thanks & Regards
Ariffpl ease check below link
/people/thomas.jung3/blog/2004/09/08/sending-e-mail-from-abap--version-610-and-higher--bcs-interface -
Exporting Data from Forms to Excel
Hi,
How can I export the data from Forms to Excel like which Export function in the Oracle Applications.
Thank you,
VoonHello,
By using dde package you can export the data from Form to Excel. Here is the sample code which i have used. you can write this code in the when_button_pressed trigger.
declare
appl_name varchar2(255);
channel_id pls_integer;
application_id pls_integer;
x number;
y number;
V_TIME VARCHAR2(30);
begin
if :global.application_id is not null then
message('Application already open');
else
appl_name := 'c:\program files\microsoft office\office\excel.exe';
:global.application_id := dde.app_begin(appl_name,dde.app_mode_normal);
end if;
if :global.channel_id is not null then
message('Communication channel already established.');
elsif :global.application_id is null then
message('Application must be launched first.');
else
:global.channel_id := dde.initiate('excel','book1');
end if;
DDE.POKE(:global.channel_id,'R1C1','Col1 Heading',DDE.CF_TEXT,1000);
DDE.POKE(:global.channel_id,'R1C2','Col2 Heading',DDE.CF_TEXT,1000);
DDE.POKE(:global.channel_id,'R1C3','Col3 Heading',DDE.CF_TEXT,1000);
FIRST_RECORD;
X := No of Records;
for y in 2..x
loop
launch_excel is a program unit--
launch_excel(y,:global.channel_id,:block.item1,:block.item2,::block.item3);
next_record;
end loop;
FIRST_RECORD;
EXCEPTION
WHEN DDE.DDE_APP_FAILURE THEN
MESSAGE('Could not launch application for DDE operations.');
RAISE FORM_TRIGGER_FAILURE;
WHEN DDE.DDE_INIT_FAILED THEN
MESSAGE('Could not initialize DDE communication channel.');
RAISE FORM_TRIGGER_FAILURE;
WHEN DDE.DMLERR_NO_CONV_ESTABLISHED THEN
MESSAGE('Could not establish DDE communication channel.');
RAISE FORM_TRIGGER_FAILURE;
WHEN OTHERS THEN
MESSAGE('Error: '| |TO_CHAR(SQLCODE)| |' '| |SQLERRM);
RAISE FORM_TRIGGER_FAILURE;
END;
LAUNCH_EXCEL
PROCEDURE LAUNCH_EXCEL(
y in number,
channel_id pls_integer,
param1 varchar2,
param2 VARCHAR2,
param3 varchar2) IS
v_rowno varchar2(20) := 'R'| |y;
BEGIN
dde.poke(channel_id,v_rowno| |'C1',col1,dde.cf_text,2000);
dde.poke(channel_id,v_rowno| |'C2',col2,dde.cf_text,2000);
dde.poke(channel_id,v_rowno| |'C3',col3,dde.cf_text,2000);
EXCEPTION
when others then
message('Error --'| |sqlcode| |sqlerrm);
message('Error --'| |sqlcode| |sqlerrm);
raise form_trigger_failure;
END;
null -
Other database delete is not working on forall statement
Dear all,
My scenario is , i create a program, the program fetch the data from database x and i want to delete on the same x database but i am running this program at y database, so
so i created a view
create or replace view vw_ibs_pda_bills_x as
SELECT *
FROM ibs_pda_bills_x@testarch1my program
Declare
CURSOR c2 IS
SELECT *
FROM vw_ibs_pda_bills_x
WHERE bill_month <= '31-dec-2008'; -- AND bpref_no = :cons;
opr varchar2(10) := 'DELETE';
TYPE tsch IS TABLE OF c2%ROWTYPE;
vtsch tsch;
cnt NUMBER := 0;
stime NUMBER;
etime NUMBER;
DURATION NUMBER;
rcount NUMBER;
errorsd PLS_INTEGER;
ecode NUMBER;
val1 VARCHAR2 (100);
val2 VARCHAR2 (100);
val3 VARCHAR2 (100);
val4 VARCHAR2 (100);
BEGIN
BEGIN
stime := DBMS_UTILITY.get_time ();
OPEN c2;
LOOP
FETCH c2
BULK COLLECT INTO vtsch LIMIT 1000;
IF vtsch.COUNT = 1000
THEN
cnt := cnt + 1;
END IF;
If opr = 'INSERT' Then
FORALL i IN 1 .. vtsch.COUNT SAVE EXCEPTIONS
INSERT INTO dlul.ibs_pda_bills
VALUES vtsch (i);
Else
FORALL i IN 1 .. vtsch.COUNT SAVE EXCEPTIONS
Delete from vw_ibs_pda_bills_x where bill_month = vtsch(i).bill_month;
End if;
EXIT WHEN c2%NOTFOUND;
END LOOP;
etime := DBMS_UTILITY.get_time ();
DURATION := ((etime - stime) / 100) / 60;
rcount :=
(cnt * 1000) + vtsch.COUNT - NVL (SQL%BULK_EXCEPTIONS.COUNT, 0);
If opr = 'INSERT' Then
INSERT INTO process_stage_log
VALUES (SYSDATE, 'IBS_PDA_BILLS', DURATION, rcount);
Else
INSERT INTO process_stage_log
VALUES (SYSDATE, 'IBS_PDA_BILLS-D', DURATION, rcount);
End if;
CLOSE c2;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
errorsd := SQL%BULK_EXCEPTIONS.COUNT;
IF errorsd > 0
THEN
FOR j IN 1 .. errorsd
LOOP
ecode := SQL%BULK_EXCEPTIONS (j).ERROR_CODE;
val1 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).sch_code;
val2 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).bpref_no;
val3 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).bill_month;
val4 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).service_code;
If opr = 'INSERT' Then
INSERT INTO process_error_log
VALUES (SYSDATE, ecode, 'IBS_PDA_BILLS', 'sch_code', val1,
'bpref_no', val2, 'bill_month', val3, 'service_code', val4,'INSERT');
Else
INSERT INTO process_error_log
VALUES (SYSDATE, ecode, 'IBS_PDA_BILLS', 'sch_code', val1,
'bpref_no', val2, 'bill_month', val3, 'service_code', val4,'DELETE');
End if;
END LOOP;
END IF;
END;
END pda_insert;the program want to do the delet option for all delete is not working. The program executed successful but the operation delete is not happening
how to solve this issue.
please help me
kanishNo error encountered in my log table
the new workaround you said, that is instead of for all , already i tried for i in 1.. to like
instead of forall delete i tried the following way
Declare
CURSOR c2 IS
SELECT *
FROM ibs_pda_bills_x@testarch1
WHERE bill_month <= '31-dec-2008'; -- AND bpref_no = :cons;
opr varchar2(10) := 'DELETE';
TYPE tsch IS TABLE OF c2%ROWTYPE;
vtsch tsch;
cnt NUMBER := 0;
stime NUMBER;
etime NUMBER;
DURATION NUMBER;
rcount NUMBER;
errorsd PLS_INTEGER;
ecode NUMBER;
val1 VARCHAR2 (100);
val2 VARCHAR2 (100);
val3 VARCHAR2 (100);
val4 VARCHAR2 (100);
BEGIN
BEGIN
stime := DBMS_UTILITY.get_time ();
OPEN c2;
LOOP
FETCH c2
BULK COLLECT INTO vtsch LIMIT 1000;
IF vtsch.COUNT = 1000
THEN
cnt := cnt + 1;
END IF;
If opr = 'INSERT' Then
FORALL i IN 1 .. vtsch.COUNT SAVE EXCEPTIONS
INSERT INTO dlul.ibs_pda_bills
VALUES vtsch (i);
Else
/* fORALL i IN 1 .. vtsch.COUNT SAVE EXCEPTIONS
Delete from vw_ibs_pda_bills_x where to_char(bill_month,'dd-mm-rrrr') = to_char(vtsch (i).bill_month,'dd-mm-rrrr');*/
for i in 1..vtsch.count loop
delete ibs_pda_bills_x@testarch1 where to_char(bill_month,'dd-mm-rrrr') = to_char(vtsch (i).bill_month,'dd-mm-rrrr');
end loop;
End if;
EXIT WHEN c2%NOTFOUND;
END LOOP;
etime := DBMS_UTILITY.get_time ();
DURATION := ((etime - stime) / 100) / 60;
rcount :=
(cnt * 1000) + vtsch.COUNT - NVL (SQL%BULK_EXCEPTIONS.COUNT, 0);
If opr = 'INSERT' Then
INSERT INTO process_stage_log
VALUES (SYSDATE, 'IBS_PDA_BILLS', DURATION, rcount);
Else
INSERT INTO process_stage_log
VALUES (SYSDATE, 'IBS_PDA_BILLS-D', DURATION, rcount);
End if;
CLOSE c2;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
errorsd := SQL%BULK_EXCEPTIONS.COUNT;
IF errorsd > 0
THEN
FOR j IN 1 .. errorsd
LOOP
ecode := SQL%BULK_EXCEPTIONS (j).ERROR_CODE;
val1 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).sch_code;
val2 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).bpref_no;
val3 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).bill_month;
val4 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).service_code;
If opr = 'INSERT' Then
INSERT INTO process_error_log
VALUES (SYSDATE, ecode, 'IBS_PDA_BILLS', 'sch_code', val1,
'bpref_no', val2, 'bill_month', val3, 'service_code', val4,'INSERT');
Else
INSERT INTO process_error_log
VALUES (SYSDATE, ecode, 'IBS_PDA_BILLS', 'sch_code', val1,
'bpref_no', val2, 'bill_month', val3, 'service_code', val4,'DELETE');
End if;
END LOOP;
END IF;
END;
END pda_insert;i am receiving the following error
ORA-02055: distributed update operation failed; rollback required
ORA-06531: Reference to uninitialized collection
ORA-06512: at line 77
ORA-06531: Reference to uninitialized collection
kanish -
How can I get the list of all canvas in the forms programatically?
I want an exemple of how to do it. I really need it to put in a template.
This is the code.
You will see how to loop through every item of every blocks of the form:
PROCEDURE Get_Canvas_Names IS
lc$blockDeb varchar2(60); -- start block
lc$block varchar2(60); -- current block name
lc$item varchar2(60); -- current item
lc$Type varchar2(20); -- item type
lc$itemdeb varchar2(60); -- first item
lc$canvas varchar2(60); -- current canvas name
lc$tabcan varchar2(60); -- current tab canvas name
lc$Acanvas varchar2(60):= ' '; -- old canvas name
lc$Atabcan varchar2(60):= ' '; -- old tab canvas name
ln$NbRec pls_integer := 0 ; -- number of records (for know if the block is multi-records)
BEGIN
LC$BlockDeb := get_form_property( NAME_IN('System.Current_Form'), FIRST_BLOCK ) ;
LC$Block := LC$BlockDeb ;
Loop -- For each block of the form
LN$NbRec := get_block_property(LC$BLOCK, RECORDS_DISPLAYED) ;
lc$itemdeb := get_block_property(LC$BLOCK, FIRST_ITEM) ;
lc$item := LC$BLOCK || '.' || lc$itemdeb ;
while lc$itemdeb is not null loop -- For each item
-- visible item ? --
IF GET_ITEM_PROPERTY(LC$Item , VISIBLE) = 'TRUE' Then
-- Get the canvas and tab canvas name --
lc$canvas := GET_ITEM_PROPERTY(LC$Item , ITEM_CANVAS ) ;
lc$tabcan := GET_ITEM_PROPERTY(LC$Item , ITEM_TAB_PAGE ) ;
End if ; -- GET_ITEM_PROPERTY(LC$Item , VISIBLE) = 'TRUE'
lc$itemdeb := get_item_property(lc$item, NEXT_NAVIGATION_ITEM );
lc$item := LC$BLOCK || '.' || lc$itemdeb ;
end loop ;
LC$Block := get_block_property( LC$Block, NEXTBLOCK ) ; -- next block
exit when LC$Block is null ;
End loop ;
END Get_Canvas_Names;all you have to do is to save each different canvas names in a pl/sql table.
Francois
Maybe you are looking for
-
Error while running ejbc. Fatal error from EJB Compiler ---- Error while pr
Hi! I was deploying a test application for a session bean with sun 1 studio 5 and I started getting this message while deploying. I had tested the bean previously and I had no problems. I found this in the sun app server 7 release notes, but I don't
-
I have Acrobat Pro X - when I go to open a PDF, it appears blank with no text. Images show up, and I can see that there is text in the document when i open through Preview, but when I ope in Acrobat, it's not there. I had unchecked "enhanced security
-
Unable to see correlation in receiver step of BPM.
Hi, I am designing a BPM in XI. In a receiver step I need a correlation. I am able to select a correlation from the drop down of the field "Activate Correlations" but when it is activated, the correlation is not displayed. I am using SAP XI 7.4 and S
-
Actively changing number of elements in an array
How do you use a control in the front panel to actively change the number of rows in an array which full of numeric controls? Is it possible to have this happen without the program to be running? Thanks for any help. Solved! Go to Solution.
-
Is there any function module to convert the date format
Dear ABAPers, Is there any function module to convert the date format from dd.mm.yyyy to dd-mmm-yyyy. I want to convert the date format from dd.mm.yyy to dd.mmm.yyy Eg.from 10.03.2008 to 10-mar-2009. Thanks & Regards, Ashok.