Write to Oracle concurrent request output / log from a SQLPlus program - sql

I have an Oracle concurrent request that calls a SQLPlus program. The program itself is working correctly, but I would like to add some logging information to the concurrent request output / log in EBS.
I have tried a number of variations of:
set heading off
--set pagesize 0 embedded on
set pagesize 50000
set linesize 32767
set feedback off
set verify off
set term off
set echo off
set newpage none
set serveroutput on
dbms_output.enable(1000000);
--prepare data
EXECUTE program (&1,&2,&3,&4,&5);
--extract data
#"path/file.SQL";
fnd_file.put_line(FND_FILE.LOG,'do some logging here');
fnd_file.put_line(FND_FILE.OUTPUT,'do some logging here');
/
But everything I've tried so far results with either
no logging added to request output or log
no request output whatsoever
errors like:
SP2-0734: unknown command beginning "dbms_outpu..." - rest of line ignored.
and
PLS-00103: Encountered the symbol "ENABLE" when expecting one of the following: := . ( # % ;
Is it possible to write to the request output or log from a SQLPlus script that is called from concurrent manager?

First of all, your SQL*Plus script does not even run without your attempts at logging.
dbms_output enable(...) is missing a dot ('.').
Your anonymous PL/SQL block has no end; statement
#"path/file.SQL` is a SQL*Plus command -- it cannot be embedded in an anonymous PL/SQL block.
Aside from those basic problems, FND_FILE.PUT_LINE is only for PL/SQL concurrent programs. That is, concurrent programs whose executable points to a PL/SQL package procedure and not a .sql file under $APPL_TOP.
For SQL*Plus concurrent programs, i.e., running a .sql file under $APPL_TOP, FND_FILE.PUT_LINE does not work. Instead, your SQL*Plus output is automatically written to the request output. There is no standard way to write to the request log.
If you really need to write to the request log, you could maybe call FND_FILE.PUT_NAMES to cause FND_FILE.PUT_LINE to write to temporary files that you name. Then, knowing the concurrent request ID and the logic Oracle EBS uses to local output and log files, do a FND_FILE.CLOSE and host command to move the custom-named files you specified to the actual locations. That might work.
It'd be much better to redo your concurrent program as a PL/SQL package. Then FND_FILE works just fine. If you know how to call Java from the database, there is very little you can do in a .sql script that you cannot do in a PL/SQL package.
I have not written a .sql concurrent program in years, and I write concurrent programs all the time.

I have resolved this problem. The solution is incredibly simple - and now I'm bent out of shape because it took so long to realize.
Step 1 - SET ECHO ON
Step 2 - PROMPT whatever you want written to concurrent request output
The following sample writes 'Output is written to this folder' to the concurrent request output.
set heading off
--set pagesize 0 embedded on
set pagesize 50000
set linesize 32767
set feedback off
set verify off
set term off
set echo on
set newpage none
set serveroutput on
prompt Output is written to this folder
--prepare data
EXECUTE program (&1,&2,&3,&4,&5);
--extract data
#"path/file.SQL";
/
This is exactly what I was looking for. Maybe this will be useful to someone in another galaxy.

If this is for testing/debugging purposes, you can specify the location of the log and output files with the routine: FND_FILE.PUT_NAMES and as soon as you log all the required information you need to close the file with: FND_FILE.CLOSE

As Matthew mentioned, logging in SQL*Plus executables doesn't work well. If you can't move your code to a PL/SQL Stored Procedure for some reason, a Host script might work for you instead. From there, you can execute SQL, e.g. sqlplus -s $FCP_LOGIN ... and write log information as required.
If you just need to prepare data by PLSQL and then spool it to CSV via SQL, you can use our company's Blitz Report instead, which does this more convenient and is for free for such use. It also uses a Host type executable and calls sqlplus from there.

Related

Oracle SQL if statement based on parameter passed in via .sh script

I have a shell script which calls some SQL like so
sqlplus system/$password#$instance #./oracle/mysqlfile.sql $var1 $var2 $var3
Then in mysqlfile.sql, I define properties like this:
DEFINE var1=&1
DEFINE var2=&3
DEFINE var3=&3
Later in the file, I call another SQL script:
// i wish to wrap this in a if statement - pseudo-code
if(var3="true") do the following
#./oracle/myOthersqlfile.sql &&varA &&varB
I am not sure how to implement this though, any suggestions appreciated
You could (ab)use substitution variables:
set termout off
column var3_path new_value var3_path
select case
when '&var3' = 'true' then './oracle/myOthersqlfile.sql &&varA &&varB'
else '/dev/null'
end as var3_path
from dual;
set termout on
#&var3_path
The query between the set termout commands - which just hide the output of the query - uses a case expression to pick either your real file path or a dummy file; I've used /dev/null, but you could have a 'no-op' file of your own that does nothing if that's clearer. The query gives the result of that the alias var3_path. The new_value line before it turns that into a substitution variable. The # then expands that variable.
So if var3 is 'true' then that runs:
#./oracle/myOthersqlfile.sql &&varA &&varB
(or, actually, with the varA and varB variables already replaced with their actual values) and if it is false it runs:
#/dev/null
which does nothing, silently.
You can set verify on around that code to see when and where substitution is happening.
You can't implement procedural logic into sqlplus. You have these options :
Implement the IF-THEN-ELSE logic inside the shell script that is running the sqlplus.
Use PL/SQL, but then your SQL Script should be called as a process inside an anonymous block, not like an external script.
In your case the easiest way is to change your shell script.
#/bin/bash
#
# load environment Oracle variables
sqlplus system/$password#$instance #./oracle/mysqlfile.sql $var1 $var2 $var3
# if then
if [ $var3 == "true" ]
then
sqlplus system/$password#$instance #./oracle/myOthersqlfile.sql
fi
You should realise that sqlplus is just a CLI ( Command Line Interface ). So you can't apply procedural logic to it.
I have no idea what you do in those sql scripts ( running DMLs, creating files, etc ), but the best approach would be to convert them to PL/SQL, then you can apply whatever logic you need to.

Oracle SQLPlus: Echo without line numbers?

I'm working on a solution where several SQL and PL/SQL scripts are being run together, in a batch of sorts, via SQL*Plus.
I'm declaring SET ECHO OFF; and SET ECHO ON; at relevant points in the scripts so as to output relevant code.
Currently the output looks something like this:
SQL> DECLARE
2 ct number := 0;
3 ctChanges number := 0;
4
5 BEGIN
6 select count(*) into ct from ...
7 (...rest of code block...)
"some specific status message"
Commit executed.
We keep this output as a run-log in our build-environment, but can also access it as a plain text file.
One downside of this format however, is that if I'd like to copy a certain section of the code and run it again in an IDE (like Toad or SQL Developer), it's hard to exclude the line numbers.
Is it possible to tell SQL*Plus to output the code as above, but without including the line numbers?
You can use options sqlnumber and sqlprompt:
set sqlprompt ''
set sqlnumber off
SET SQLN[UMBER] {ON|OFF}
SET SQLNUMBER is not supported in iSQL*Plus
Sets the prompt for the second and subsequent lines of a SQL command or PL/SQL block. ON sets the prompt to be the line number. OFF sets the prompt to the value of SQLPROMPT.

How can I run my Rexx program as a batch job?

I have a Rexx program that I want to run as a batch job. How can I do this?
This is my program :-
/* Rexx – HELLO – Write Hello World */
Say "hello World"
The program is located as member HELLO in the PDS ME.USER.EXEC.
A valid JOB CARD for my installation is (our environment includes ISPF/PDF as opposed to ROSCOE):-
//MYJOB JOB ,,CLASS=1,MSGCLASS=H,NOTIFY=&SYSUID
Note! this has been written as a tutorial
There are a number of ways that you can run the program via batch. I will cover 3 ways all of which are different according to the environment (i.e. what they can utilise.)
Method 1 - Run the program in a Rexx environment.
This entails running the program IRXJCL and passing the name of the program (i.e. the PDS's member name) via the PARM field (you can also pass parameters; accessing them via a PARSE ARG statement).
IRXJCL requires (normally) 3 DDNAMES they are SYSEXEC (The PDS where the program is located), SYSTSIN (this can reflect terminal input) and SYSTSPRT (this is where terminal output is sent).
Here is the JCL that would work according the information provided above:-
//MYJOB JOB ,,CLASS=1,MSGCLASS=H,NOTIFY=&SYSUID
//*-------------------------------------------------------------------
//RUNPROG EXEC PGM=IRXJCL,PARM=’HELLO’
//*
//* RUN OUR REXX PROGRAM CALLED HELLO
//*
//SYSEXEC DD DSN=ME.USER.EXEC,DISP=SHR
//SYSTSIN DD DUMMY
//SYSTSPRT DD SYSOUT=*
//*-------------------------------------------------------------------
This method, although the simplest (by just a few lines of JCL), is the most restrictive in that it does not allow the use of
TSO/E services, such as TSO/E commands and most of the TSO/E external
functions.
However, as IRXJCL is a Rexx processor, there is no requirement to let
TSO/E know that it is a Rexx program (the first line must include
REXX).
Method 2 - Run the program from a TSO/E environment
This entails running one of the TSO/E batch processing programs IKJEFT01 is used in this example. Alternatives are IKJEFT1A and IKJEFT1B. TSO/E services and commands can be used via this method (e.g. note at end of this method using the TIME command)
Comprehensive information about the differences between the programs
can be found at Writing JCL for command
execution
The JCL for IKJEFT01 is similar to that used in Method 1. An additional DDNAME SYSPROC can be coded. SYSPROC is the DDNAME where CLISTS would be located; You can have Rexx programs found here in addition to SYSEXEC (which isn't required, a suggestion is that both are coded and that SYSEXEC is used for Rexx programs and SYSPROC is used for CLISTS).
It's the requirement that Rexx is on the first line that
differentiates a Rexx program from a CLIST (by the TSO/E processor). Thus, if the Rexx program is found/located via SYSEXEC, if I recall correctly, this negates the requirement).
Another suggestion is to always include REXX in the first line of a Rexx program>
The EXEC statement invokes the IKJEFT01 program instead of IRXJCL. PARM can be used to specify the first command (and therefore our HELLO program). However, as for foreground, you can specify this via the terminal i.e. the SYSTSIN DDNAME.
Here is some JCL that would work for the second method; noting that the HELLO program is invoked via the SYSTSIN DDNAME as instream data :-
//MYJOB JOB ,,CLASS=1,MSGCLASS=H,NOTIFY=&SYSUID
//*-------------------------------------------------------------------
//RUNPROG EXEC PGM=IKJEFT01
//*
//* RUN OUR REXX PROGRAM CALLED HELLO IN A TSO/E ENVIRONMENT
//*
//SYSPROC DD DSN=ME.USER.CLIST,DISP=SHR
//SYSEXEC DD DSN=ME.USER.EXEC,DISP=SHR
//SYSTSIN DD *
HELLO
//SYSTSPRT DD SYSOUT=*
//*-------------------------------------------------------------------
If, for example, the following were used (i.e. added TIME as another
line to SYSTSIN) then the TSO/E TIME command would be run (which would
cause the time to be displayed to SYSTSPRT).
//SYSTSIN DD *
HELLO
TIME
Method 3 - Run the program in an ISPF environment
This method uses the IKJEFT01 program (see method 2 for IKJEFT1A/B alternatives). However, it then uses the ISPSTART command to run the program in an ISPF environment; enabling the use of ISPF services (e.g file tailoring (skeletons) ISPF tables etc).
An ISPF environment has additional requirements in that ISPF libraries need to be allocated in order to start an ISPF environment. At a minimum have the supplied ISPF libraries allocated to ddnames ISPPLIB (ISPF Panels), ISPMLIB (ISPF Messages) & ISPTLIB (ISPF Tables). ISPPROF is where ISPF keeps some profile data for the session, so a temporary store is sufficient (UNIT=SYSDA is often available if not always).
Note you would likely allocate, at a minimum, the installations system
libraries (the TSO/E command LISTA can likely be used to determine
these from a foreground session). Alternately, ask you local friendly system programmers. In the following they are SYS1.ISPPLIB, SYS1.ISPMLIB and SYS1.ISPTLIB.
Here is some JCL that would work for the 3rd method. Note that HELLO is passed as a parameter to the ISPSTART command.
//MYJOB JOB ,,CLASS=1,MSGCLASS=H,NOTIFY=&SYSUID
//*-------------------------------------------------------------------
//RUNPROG EXEC PGM=IKJEFT01
//*
//* RUN OUR REXX PROGRAM HELLO IN A TSO/E/ISPF ENVIRONMENT
//*
//SYSPROC DD DSN=ME.USER.CLIST,DISP=SHR
//SYSEXEC DD DSN=ME.USER.EXEC,DISP=SHR
//ISPPLIB DD DSN=SYS1.ISPPLIB,DISP=SHR
//ISPMLIB DD DSN=SYS1.ISPMLIB,DISP=SHR
//ISPTLIB DD DSN=SYS1.ISPTLIB,DISP=SHR
//ISPPROF DD UNIT=SYSDA,SPACE=(CYL,(10,1)),
// RECFM=FB,LRECL=80,BLKSIZE=0
//SYSTSIN DD *
ISPSTART CMD(HELLO)
//SYSTSPRT DD SYSOUT=*
//*-------------------------------------------------------------------
Note this is not a fully comprehensive, it is an overview that should
suffice for getting started with running Rexx programs in batch.
Additional comments to the above answer.. The below technote may be helpful if you wish to run your REXX exec using ISPF services...
http://www.ibm.com/support/docview.wss?uid=swg21023990
Make sure that the ISPPROF file is concatenated as the first file in ISPTLIB. The example uses a temporary file that will be unique to the job. If the REXX exec does table services you may need an ISPTABL DD. I would suggest using the same file for ISPPROF and ISPTABL and concatenate it first in ISPTLIB. This can be a permanent file if the table needs to be save, however it should not be in use by other jobs or TSO users so as to avoid enqueue errors.
As the previous update stated his answers suffice for the simple REXX exec.
Yet more additional comments to the answer by MikeT...
Suppose you want your JCL to be self-contained: you want to include a REXX exec as an in-stream data set in the JCL, rather than referring to a REXX exec stored in a PDS member.
Here's the "trick" (for IRXJCL; I haven't tested this trick with other programs): specify a single null (X'00') byte as the value of the PARM attribute of the EXEC statement.
To specify the null byte, use the z/OS ISPF editor with HEX ON:
//REXX EXEC PGM=IRXJCL,PARM=' '
66DCEE44444CECC4DCD7CDEDCD6DCDD7707
1195770000057530774E997133B7194ED0D
For example, if you entered PARM=' ' with a space as the value, overtype the 4 of the hex value of that space with a 0.
Here's an example job step containing an in-stream REXX exec that processes the output from a previous step in the same job:
//* PARM value is a single X'00' byte
//REXX EXEC PGM=IRXJCL,PARM=' '
//SYSEXEC DD DATA,DLM=$$
/*
Transposes first line of input CSV into one record per field
Reads CSV from ddname SYSTSIN.
Writes output to ddname SYSTSPRT.
*/
columnSeparator = ","
/* Get the header row */
parse pull row
/* Get column names */
do i = 1 until row = ""
parse value row with columnName "," row
say columnName
end
exit 0
$$
//SYSTSIN DD DSN=&&CSV,DISP=OLD
//SYSTSPRT DD SYSOUT=*
Notes:
In this context, the first line of the REXX exec does not need to contain the string "REXX"
DLM=$$ enables you to use REXX comment syntax (/*) without prematurely ending the in-stream data set
&&CSV refers to a CSV file created by a previous job step (not shown)
I use this "in-stream REXX" technique mostly for ad hoc execs to transform the output of a batch program into what I really want. This technique can be useful for demonstrations and quickly bouncing ideas around; other developers can view the REXX code in situ in the JCL in SDSF output, tweak it, and then submit the tweaked version.

Oracle how to print some message?

As we know in MSSQL we can write below line to print some message
print 'Some Message';
How we can do same in Oracle as print not working with Oracle?
Use
DBMS_OUTPUT.put_line('Some Message');
To expand on #mhasan's answer and #AlexPoole's comment: assuming that you're executing your script using SQL*Plus you'll need to add the beginning of your script before the first DECLARE or BEGIN:
SET SERVEROUTPUT ON SIZE 1000000
SET LINESIZE 255
If you're using a tool other than SQL*Plus to run your script there will be different ways to view output written to DBMS_OUTPUT. For example, in PL/SQL Developer a "Test" window has a "DBMS Output" tab where text written to DBMS_OUTPUT can be viewed after the test script terminates.
Share and enjoy.

Increase buffer size in JBSQL

I have some Oracle PL?SQL code that a user is trying to run using the JBSQL tool
There are a few dbms_output lines - when the user runs the code they get an error
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
How do I increase the buffer size?
I've tried
SET SERVEROUTPUT ON SIZE 1000000;
but get "unknown option size". Is there a "default" command regardless of the tool to set the buffer size? Or can I add anything to my PL/SQL?
(Eventually I will write the lines to a table/text file but need to get this procedure up and running to show it is worthwhile - everything works absolutely fine - just the bit that notifies the user at the end!!!)
Any help gratefully received
Thanks
Mike
SET SERVEROUTPUT is a SQL*Plus command, it is not a SQL or PL/SQL command. It will only work in SQL*Plus or SQL*Plus-like tools (Toad, SQL developer...).
You can use DBMS_OUTPUT.enable(buffer_size) to increase the default output buffer size. Note however that your error could come from somewhere else: ORA-06502 is a generic error that can be raise by any assignment where the variable is too small.
SET SERVEROUTPUT ON SIZE n; is an SQL*Plus command, but many editors allow to use it. Anyways, can you try this instead:
BEGIN
DBMS_OUTPUT.ENABLE(BUFFER_SIZE => 1000000);
END;
What version of JBSql are you using? Normally, since version 1.1.0.2 the buffer size has been increased from 255 to 32767 characters. If it still fails with the latest version (1.3.0.0), then please provide a testcase to http://duofoto.be/mantis