Skip to Main Content
  • Questions
  • Executing code across a database link

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, David .

Asked: April 08, 2003 - 8:23 am UTC

Last updated: September 16, 2008 - 10:59 pm UTC

Version: 8.0.6

Viewed 10K+ times! This question is

You Asked

Morning, Tom.

Our production database is terminal at 8.0.6. But we have a number of other servers running 8i and 9i. I'd like to take advantage of some of the 8i and 9i functionality, but do it within the production database.

For example, I have a send_mail procedure on the 9i machine (using utl_smtp), and I'd like to fire it off based on values in the production database, on the 8.0.6 machine.

If this is possible, what approach would you recommend?

As always, thanks.

David

and Tom said...

it is possible and I used to do it myself in fact.

Here is what I did. I set up a package on the "mail enabled database"

create package my_pkg
as
procedure send_mail( p_to, p_from, p_subj, p_body );
procedure background_send_mail( p_job in number );
end;
/

create table send_mail_queue ( job int primary key, to, from, subj, body );


Now, the send mail job just did this


as
dbms_job.submit( l_job, 'background_send_mail(JOB);' );
insert into send_mail_queue( l_job, .... );
end;



The send-mail-background was like this:


is
select * into l_rec from send_mail_queue where job = p_job;
... send the mail;
delete from send_mail_queue where job = p_job;
commit;
end;



Now, you just need to call my_pkg.send_mail@remote_site (suggest creating a synonym for my_pkg@remote_site for when you migrate this to 10i or whatever later). It'll queue a job that will run after you commit on the remote site.



Rating

  (10 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

See what you think of this

David, April 08, 2003 - 1:36 pm UTC

CREATE OR REPLACE TRIGGER test_trigger after insert or update of dummy on t1
for each row WHEN (1=1)
declare

value varchar2(1);

begin

value := :new.dummy;

send('You inserted '|| value || ' into t1.dummy' );

end;
/

CREATE OR REPLACE procedure send (p_message in varchar2) as

begin

send_mail@omslab('user@xxx.com','user@xxx.com','sent from database',p_message);

end;
/

On the remote DB

CREATE OR REPLACE procedure send_mail
( p_sender in varchar2,
p_recipient in varchar2,
p_subject in varchar2,
p_message in varchar2 ) as


l_mailhost varchar2(255) := 'xx.xx.xx.xxx' ;
l_mail_conn utl_smtp.connection ;
l_header varchar2(1000);
crlf varchar2(2):= utl_tcp.crlf;

begin

l_header:= 'Date: ' || to_char(sysdate -1,'dd Mon yy hh24:mi:ss')||crlf||
'From: ' || p_sender || '' || crlf ||
'Subject: ' || p_subject || crlf ||
'To: ' || p_recipient;



l_mail_conn
:= utl_smtp.open_connection(l_mailhost, 25) ;

utl_smtp.helo(l_mail_conn, l_mailhost) ;

utl_smtp.mail(l_mail_conn, p_sender) ;

utl_smtp.rcpt(l_mail_conn, p_recipient ) ;

utl_smtp.open_data(l_mail_conn) ;

utl_smtp.write_data(l_mail_conn, l_header);

utl_smtp.write_data(l_mail_conn, crlf || p_message);

--utl_smtp.write_data(l_mail_conn, p_message ) ;

utl_smtp.close_data(l_mail_conn) ;

utl_smtp.quit(l_mail_conn );


end ;
/


*******

So when a value is inserted into the table, an email is sent with the value.

Pretty basic, but it's a prototype at the moment. I'm working on getting the distibution to be dynamic.

Thanks as always for your help.

David

Tom Kyte
April 08, 2003 - 1:57 pm UTC

Nope, I would use dbms_job to

a) make it appear blazingly fast. (utl_smtp uses a blocking call -- it'll take a second)
b) make it transactional (roll back that insert -- drat, got an email anyway)

if you have my book expert one on one Oracle -- i flesh this concept out fully.

I said it was a prototype!

David, April 08, 2003 - 2:04 pm UTC

;-)

With yours, I'm trying to figure out what drives the 'job' value. Are these different distributions and messages for specific applications?

Tom Kyte
April 08, 2003 - 5:35 pm UTC

see below

What is the meaning of JOB?

Logan Palanisamy, April 08, 2003 - 3:12 pm UTC

Tom,

You have created the send_mail procedure as

"
as
dbms_job.submit( l_job, 'background_send_mail(JOB);' );
insert into send_mail_queue( l_job, .... );
end;
"

What is JOB in 'background_send_mail(JOB)'? Is it a variable or the value itself? If variable where is declared?

It is a little confusing. It is an excellent technique otherwise.

Thanks

Tom Kyte
April 08, 2003 - 5:45 pm UTC

Ok, maybe it'll sell a book or two. Here is a lengthly extract from my book "Expert One on One Oracle" that describes this in painstaking detail:

....

The main routine you will use with DBMS_JOB is the SUBMIT routine. Its interface is as follows:

PROCEDURE SUBMIT
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
JOB BINARY_INTEGER OUT
WHAT VARCHAR2 IN
NEXT_DATE DATE IN DEFAULT
INTERVAL VARCHAR2 IN DEFAULT
NO_PARSE BOOLEAN IN DEFAULT
INSTANCE BINARY_INTEGER IN DEFAULT
FORCE BOOLEAN IN DEFAULT

Where the arguments to the SUBMIT routine have the following meanings:

o JOB: is a job identifier. It is system assigned (it is an OUT only parameter). You can use this to query the USER_JOBS or DBA_JOBS views by job id to see information about that job. Additionally some routines such as 'run' and 'remove' take the job id as their only input to uniquely identify the job to run or remove.

o WHAT: is the SQL Text of what will be run. It must be a valid PL/SQL statement or block of code. For example, to run a stored procedure P, you might pass the string P; (with the semi-colon) to this routine. Whatever you submit in the WHAT parameter will be wrapped in the following PL/SQL block:

DECLARE
job BINARY_INTEGER := :job;
next_date DATE := :mydate;
broken BOOLEAN := FALSE;
BEGIN
WHAT

:mydate := next_date;
IF broken THEN :b := 1; ELSE :b := 0; END IF;
END;

That is why you need to add the ';' to any statement - in order to just replace the WHAT with your code, it will need a semi-colon

o NEXT_DATE: Is the next (or since we are just submitting the first) time to run the job. The default is SYSDATE - run as soon as possible (after committing).

oINTERVAL: Is a string containing a date function that calculates the next time to run the job. You can consider this function to be 'selected from dual'. If you pass in the string 'sysdate+1', the database will in effect execute 'select sysdate+1 into :next_date from dual'. See below for some caveats on setting the interval of a job to prevent 'sliding'.

o NO_PARSE: Determines whether the WHAT parameter is parsed upon submission. By parsing the string - you can be reasonable sure the string is in fact executable. In general, NO_PARSE should always be left with its default of FALSE. When set to true, the WHAT parameter is accepted 'as is' with no validity checking.

o INSTANCE: Is only meaningful in Parallel Server mode, a mode Oracle can run in on a loosely coupled cluster of machines. This would specify the instance upon which this job should be executed. By default, this will have a value of ANY_INSTANCE.

o FORCE: Again, this is only meaningful in Parallel Server mode. If set to TRUE (the default) you may submit the job with any instance number - even if that instance is not available at the time of job submission. If set to FALSE, submit will fail the request if the associated instance is not available.

....

Now that we have a working knowledge of how DBMS_JOB works and what functions are available to us, we'll look at how to run a job once, how to set up a recurring job correctly, and how to monitor our jobs and find out what errors they have encountered.


Running a job once


Many of the jobs I run are 'one off' jobs. I use DBMS_JOB much as one would use the & in Unix or the start command in Windows to run a process in the background. The example I gave above with regards to sending email is a good example. I use DBMS_JOB to make the sending of email not only transactional but appear to be fast. Here is one implementation of that to demonstrate how to run a job once. We'll start with a small stored procedure to send mail using the supplied UTL_SMTP package:

tkyte@TKYTE816> create or replace
2 PROCEDURE send_mail (p_sender IN VARCHAR2,
3 p_recipient IN VARCHAR2,
4 p_message IN VARCHAR2)
5 as
6 -- NOTE that you have to use a host
7 -- that supports SMTP and that you have access to.
8 -- you do not have access to this host and must change it
9 l_mailhost VARCHAR2(255) := 'aria.us.oracle.com';
10 l_mail_conn utl_smtp.connection;
11 BEGIN
12 l_mail_conn := utl_smtp.open_connection(l_mailhost, 25);
13 utl_smtp.helo(l_mail_conn, l_mailhost);
14 utl_smtp.mail(l_mail_conn, p_sender);
15 utl_smtp.rcpt(l_mail_conn, p_recipient);
16 utl_smtp.open_data(l_mail_conn );
17 utl_smtp.write_data(l_mail_conn, p_message);
18 utl_smtp.close_data(l_mail_conn );
19 utl_smtp.quit(l_mail_conn);
20 end;
21 /

Procedure created.

Now, to time how long that takes - I'll run it two times:

tkyte@TKYTE816> set serveroutput on
tkyte@TKYTE816> declare
2 l_start number := dbms_utility.get_time;
3 begin
4 send_mail( 'asktom_us@oracle.com',
5 'asktom_us@oracle.com', 'hey there' );
6 dbms_output.put_line
7 ( round( (dbms_utility.get_time-l_start)/100, 2 ) ||
8 ' seconds' );
9 end;
10 /
.81 seconds

PL/SQL procedure successfully completed.

tkyte@TKYTE816> /
.79 seconds

PL/SQL procedure successfully completed.

It looks like that will consistently take on the order of 8/10's of a second to send a mail during the best of times. As far as I am concerned, that is far too long. We can do much better - well, we can do much 'apparently' better. We'll use jobs to give this the appearance of being much faster - and gain the benefit of a 'transactional' email as well.

We will start by creating a table to store the email and a procedure we could run against this table to send an email. This procedure will ultimately become our background job. A question is - why am I using a table to store the emails? Why not just pass parameters to the job? The reason is bind variables and the shared pool. Since all jobs are created using the WHAT parameter - and the database will simply 'execute' that string at run time, we want to make sure that the WHAT parameter we submit is something that will be in the shared pool. We could easily just submit a job such as:

dbms_job.submit( x, 'send_mail(''asktom_us@oracle.com'',
''asktom_us@oracle.com'', ''hello'' );' );

but that would have the effect of flooding our shared pool with hundreds or thousands of unique statements - killing our performance. Since we plan on sending lots of emails (anything more than 1 is lots and would mandate the use of bind variables) - we need to be able to submit something like:

dbms_job.submit( x, 'background_send_mail( constant );' );

Well, as it turns out there is an easy way to do this. We simply need to create a table that contains a field for each parameter we really wanted to send to the routine (sender, recipient, message in this case) plus an ID primary key field. For example:

tkyte@TKYTE816> create table send_mail_data( id number primary key,
2 sender varchar2(255),
3 recipient varchar2(255),
4 message varchar2(4000),
5 senton date default NULL );

Table created.

Here I added an ID column as a primary key - and in this case a sent on senton column. We'll use this table not only as a place to queue up outgoing emails but to keep a persistent log of emails sent and when they were sent (very handy, trust me, for when people say "but I didn't get the notification"). Now all we need to do is figure out a way to generate a key for this table and get it to our background process using a constant string. Fortunately DBMS_JOB already does that for us. When we schedule a job, it automatically creates a job id for it and returns that to us. Since the block of code it wraps around our WHAT parameter includes this job id, we can simply pass it to ourselves! That means, our fast_send_mail routine will look like this:

tkyte@TKYTE816> create or replace
2 PROCEDURE fast_send_mail (p_sender IN VARCHAR2,
3 p_recipient IN VARCHAR2,
4 p_message IN VARCHAR2)
5 as
6 l_job number;
7 begin
8 dbms_job.submit( l_job, 'background_send_mail( JOB );' );
9 insert into send_mail_data
10 ( id, sender, recipient, message )
11 values
12 ( l_job, p_sender, p_recipient, p_message );
13 end;
14 /

Procedure created.

This routine will submit a job background_send_mail and pass it the JOB parameter. If you refer to the WHAT parameter description above - you'll see the block of code includes 3 local variables we have access to - we are simply passing ourselves one of them. The very next thing we do in this procedure is to insert the email into our queue table - for delivery later. So, DBMS_JOB creates the primary key, then we insert the primary key with the associated data into this table. That's all we need to do. Now, we need to create the background_send_mail routine and it is simply:

tkyte@TKYTE816> create or replace
2 procedure background_send_mail( p_job in number )
3 as
4 l_rec send_mail_data%rowtype;
5 begin
6 select * into l_rec
7 from send_mail_data
8 where id = p_job;
9
10 send_mail( l_rec.sender, l_rec.recipient, l_rec.message );
11 update send_mail_data set senton = sysdate where id = p_job;
12 end;
13 /

Procedure created.

It reads out the data we saved, calls the slow send_mail routine and then updates the record to record the fact that we actually sent the mail. Now, we can run fast_send_mail and see how fast it really is:

tkyte@TKYTE816> declare
2 l_start number := dbms_utility.get_time;
3 begin
4 fast_send_mail( 'asktom_us@oracle.com',
5 'asktom_us@oracle.com', 'hey there' );
6 dbms_output.put_line
7 ( round( (dbms_utility.get_time-l_start)/100, 2 ) ||
8 ' seconds' );
9 end;
10 /
.03 seconds

PL/SQL procedure successfully completed.

tkyte@TKYTE816>
tkyte@TKYTE816> declare
2 l_start number := dbms_utility.get_time;
3 begin
4 fast_send_mail( 'asktom_us@oracle.com',
5 'asktom_us@oracle.com', 'hey there' );
6 dbms_output.put_line
7 ( round( (dbms_utility.get_time-l_start)/100, 2 ) ||
8 ' seconds' );
9 end;
10 /
.02 seconds

PL/SQL procedure successfully completed.

As far as our end users are concerned - this fast_send_mail is 26 to 40 times faster then the original send mail. It is not really, it just appears to be that much faster (and that is what really counts). The actual sending of the mail will happen in the background after they commit. That is an important note here: if you run this example, make sure you commit when using the DBMS_JOB example else the email will never get sent. The job will not be visible to the job queue processes till you do (your session can see the job in the USER_JOBS view - but the job queue processes won't see it until you commit). Don't take this as a limitation - it is actually a feature, we've just made email transactional. If you rollback, so does your send mail. When you commit, it'll be delivered.


Awesome

dharma, December 19, 2003 - 3:14 pm UTC

Cant beat you!!!!

Time taken from job that get executed immidiately and there log

Vikas Sharma, October 30, 2004 - 12:02 pm UTC

Hi Tom,

I would i see the log of the job executed immediatly. OR there are no entries are done the job table when a job is executed to run immediatly. for eg i did following.

sql> variable vnum number

begin
dbms_job.submit(:vnum,'myproc(JOB);');
commit;
end;
/
sql>print
VNUM
----------
2

sql> select total_time from user_jobs where job = 2;

no rows selected
sql>

This job executed sucessfully. I want to know how much time it has been taken if i execute a procedure through a job submit.

Also please let me know what are the other parameter(bind variable) like JOB which we can use to pass as parameter.

Thanks

Vikas Sharma


Tom Kyte
October 30, 2004 - 2:14 pm UTC

if you do a one time job, not a recurring job, there is no record left behind -- it just runs and exits and cleans itself up.

You would log this yourself, the job would become something like:


dbms_job.submit(:n, 'declare n number; begin n := dbms_utility.get_time; myproc(job); n := dbms_utility.get_time-n; insert into your_own_special_log_table values ( ......, n ); end;'


do you have Expert One on One Oracle? I covered dbms_job in gory detail in that book in the appendix, showing you how to use NEXT_DATE, another parameter.

dbms_job and public db link

Ajeet, November 08, 2004 - 9:41 am UTC

Tom,
I have a procedure which gets data from a remote database (using a public db link) and it works fine if i run it from sqlplus..
When I tried to schedule it using a dbms_job..it fails and it gives an error like this

TIMESTAMP
--------------------
ERROR_MSG
------------------------------------------------------------------
ORA-01017: invalid username/password; logon denied
ORA-02063: preceding line from EVNRDWQ2-error in SA insert


I have used this script (from this site) to schedule and insert errors into a table.

create table log_table(timestamp date,error_msg varchar2(4000)) ;
declare
l_job integer ;
begin
dbms_job.submit( l_job,
'declare
msg varchar2(4000);
--
begin
ops$rdetl.rdo_sea_alert_prc ;
exception
when others then
msg := sqlerrm;
rollback;
insert into log_table
values
(sysdate,msg);
commit;
end;',
sysdate,'sysdate+1/24/60' );
end ;
/
--
The procedure is owned by a user ops$rdetl --which does exist at both oracle instances..local as well as remote..

dbms_job is also scheduled by using same user as above.

when i run the same procedure using the same user id -- it works as expected.
I tried to use authid as current_user --it did not help .

thanks

Ajeet

Tom Kyte
November 08, 2004 - 4:51 pm UTC

when you run with dbms_job, there is 'no password' available to be sent over.

if you create a private link with the username/password to be used, it will work.

Very good, but a problem appeared and I need some advice...

Sven Bleckwedel, November 17, 2004 - 4:02 pm UTC

Hi Tom,

Because of the fact mentioned below, I adopted these procedures to send messages to the clients.  I proved and can certify that was as you described:

"
As far as our end users are concerned - this fast_send_mail is 26 to 40 times faster then the original send mail. It is not really, it just appears to be that much faster (and that is what really counts). The actual sending of the mail 
will happen in the background after they commit. That is an important note here...
"

But, noted that could have a problem when something is wrong with the SMTP server, like this little example:

SQL> CREATE OR REPLACE
  2  PROCEDURE send_mail(sender     IN VARCHAR2,
  3                      recipient  IN VARCHAR2,
  4                      subject    IN VARCHAR2,
  5                      message    IN VARCHAR2)
  6  IS
  7    mailhost  VARCHAR2(30) := 'smtp.somedomain.com.br';
  8    mail_conn utl_smtp.connection;
  9    crlf      VARCHAR2(2):= CHR(13) || CHR(10);
 10    mesg      VARCHAR2(200);
 11  BEGIN
 12    mail_conn := utl_smtp.open_connection(mailhost, 25);
 13    mesg:= 'Subject: '|| subject || crlf ||
 14  --         'X-Priority: 1' || crlf ||
 15           'To: '|| recipient || crlf || crlf ||
 16           message || crlf || 'Enviada em: ' || TO_CHAR( SYSDATE, 'dd/MM/rrrr hh24:mi:ss');
 17    utl_smtp.helo(mail_conn, mailhost);
 18    utl_smtp.mail(mail_conn, sender);
 19    utl_smtp.rcpt(mail_conn, recipient);
 20    utl_smtp.open_data(mail_conn);
 21    utl_smtp.write_data(mail_conn, mesg);
 22    utl_smtp.close_data(mail_conn);
 23    utl_smtp.quit(mail_conn);
 24  EXCEPTION
 25    WHEN utl_smtp.transient_error OR utl_smtp.permanent_error THEN
 26      BEGIN
 27        utl_smtp.quit(mail_conn);
 28      EXCEPTION
 29        WHEN utl_smtp.transient_error OR utl_smtp.permanent_error THEN
 30          NULL; -- When the SMTP Server is down or unavailable, we don´t
 31                -- have a connection to the server.  The quit call will
 32                -- raise an exception that we can ignore.
 33      END;
 34      raise_application_error(-20999,'Falha no envio de e-mail devido ao erro: '||sqlerrm);
 35  END;
 36  /

Procedure created.

SQL> show errors
No errors.

SQL> begin
  2  envia_msg( 'sender@somedomain.com.br',
  3             'recipient@anotherdomain.com.br',
  4             'Alert message...',
  5             'Some subject, as example...' );
  6  end;
  7  /
begin
*
ERROR at line 1:
ORA-20999: Falha no envio de e-mail devido ao erro: ORA-29279: erro permanente de SMTP: 530 Authentication...
ORA-06512: em "FISCAL.SEND_MAIL", line 33
ORA-06512: em line 2

And noted that when the error above occurs, your procedure update the SENTON field, without having success in sending the message !  I hope that this was not waited for:

tkyte@TKYTE816> create or replace
  2  procedure background_send_mail( p_job in number )
  3  as
  4          l_rec   send_mail_data%rowtype;
  5  begin
  6          select * into l_rec
  7            from send_mail_data
  8           where id = p_job;
  9
 10          send_mail( l_rec.sender, l_rec.recipient, l_rec.message );
 11          update send_mail_data set senton = sysdate where id = p_job; <--- This update occur when having failures or success
 12  end;
13  /

In my production database, I changed the send_mail procedure to a send_html_mail function to get when errors like these could occur, only to update when the message was really "sent".  But thinked about this problem, because the messages in the queue was gone (I checked this...) !  I imagine that this is a "side effect" of this procedure, when using DBMS_JOB.  Could you give some advice about how can I do to maintain the job (the same ID) in the queue when these type of problems occur ?

Tks in adv,
Sven
 

Tom Kyte
November 17, 2004 - 4:42 pm UTC

i don't see a delete in there anywhere? so how can the message be removed??

i'm sorry but that update is *not* happening. you'll have to prove that, you don't need jobs or utl_mail -- just change send_mail to be raise_application_error() and show us the update happening.

More comments to clarify, but the focus in on the message queue...

Sven Bleckwedel, November 17, 2004 - 7:45 pm UTC

Hi Tom,

Maybe I hadn´t explained well the right point of this question in my previous message, but I will add more information to clarify, to be enough to you to give me some advice about what is happening, when using these resources.

>i don't see a delete in there anywhere? so how can the
>message be removed??

It´s nothing about deletes, because:

- The referred message was not the data in the table, but the e-mail message sended via DBMS_JOB;
- The message (e-mail!) don´t arrived in the client inbox;
- The jobs queue don´t show the (same) IDs "pending" to be sended (i.e., appear to be sended a next time, in the queue...), when some problems (like SMTP server unavailable or something else, for example...) appear;

>i'm sorry but that update is *not* happening.  you'll have
>to prove that, you don't need jobs or utl_mail -- just
>change send_mail to be raise_application_error() and show
>us the update happening.

I can´t agree with you, because you original procedure had not the exception clause.  I appended it to your original procedure the exception clause, after reading your advice about this in another review (I can´t remember it, by now...).  But mentioned you original code of send_mail, below:

tkyte@TKYTE816> create or replace
  2  PROCEDURE send_mail (p_sender       IN VARCHAR2,
  3                       p_recipient IN VARCHAR2,
  4                       p_message   IN VARCHAR2)
  5  as
  6     -- NOTE that you have to use a host
  7     -- that supports SMTP and that you have access to.
  8     -- you do not have access to this host and must change it
  9     l_mailhost VARCHAR2(255) := 'aria.us.oracle.com';
 10     l_mail_conn utl_smtp.connection;
 11  BEGIN
 12     l_mail_conn := utl_smtp.open_connection(l_mailhost, 25);
 13     utl_smtp.helo(l_mail_conn, l_mailhost);
 14     utl_smtp.mail(l_mail_conn, p_sender);
 15     utl_smtp.rcpt(l_mail_conn, p_recipient);
 16     utl_smtp.open_data(l_mail_conn );
 17     utl_smtp.write_data(l_mail_conn, p_message);
 18     utl_smtp.close_data(l_mail_conn );
 19     utl_smtp.quit(l_mail_conn);
 20  end;
 21  /

You could see that without any exception, the next step in execution of your (original) code could execute the update.  When I removed the "if..end if" from the update clause in my background_send_mail (before) this was the result (i.e., update), without seeing that the message appeared in my inbox, when testing:

SQL> create or replace procedure background_send_mail( p_job in number )
  2  as
  3     l_rec   send_mail_data%rowtype;
  4     l_status varchar2(10) default null;
  5  begin
  6     select * into l_rec
  7     from send_mail_data
  8     where id = p_job;
  9     l_status := html_email2( l_rec.recipient,
 10                              l_rec.sender,
 11                              l_rec.subject,
 12                              'Relatorio da DAD',
 13                              '',
 14                              l_rec.message );
 15     if l_status = 'SUCCESS!' then
 16        update send_mail_data set senton = sysdate where id = p_job;
 17     end if;
 18  end;
 19  /

Procedure created.

SQL> show errors
No errors.

But this was not the main point in asking you about some advice in this specific issue.  I need to understand why the job is removed (from the job queue) even when some errors appeared during the execution of the job (internally), because these jobs disappear from the job queue and the "message" was gone.  I had not conditions about how to check this (what is happening in this specific case, when using DBMS_JOB), but this was the main reason in asking you about this, maybe to be possible to you give some advice about how to trace what is happening with the sending-mail jobs...

Tks in adv,
Sven
 

Tom Kyte
November 18, 2004 - 10:13 am UTC

I need to understand why the job is removed (from the job queue) even
when some errors appeared during the execution of the job (internally), because
these jobs disappear from the job queue and the "message" was gone....

that is NOT happening is my point -- unless your job catches and ignores the error.


You will have to provide an ENTIRE TEST CASE (remember -- utl_smtp isn't relevant here -- just make send_mail be "raise....") that shows a job that failed getting removed -- for the simple reason that it doesn't work like that.

So, I can only assume that your job is really something like:

dbms_job.submit( l_job, 'begin send_.... exception when others log_error; end;' )

that when others without a raise makes the error go "poof", the job "succeeded"

I'm guessing that is what you have done, and I have to guess cause you have a partial example here.

job scheduling

senthil, September 16, 2008 - 3:37 am UTC


hi tom
i created a procedure to calculate interest i need a solution for job sheduling that should run on 1st of every month,i need stepwise procedure to write scheduling

thanks for your time
Tom Kyte
September 16, 2008 - 10:59 pm UTC

well, you should read up on dbms_job or dbms_scheduler.

I believe you want to understand what you are doing - not just be told what to do. Scheduling a recurring job is something you'll want to do over and over - so research those two packages (dbms_scheduler is preferred if you can use it, better logging facilities)

literals instead of binds?

Edgar, July 16, 2014 - 1:52 pm UTC

Recently i hit a problem with similar implementation -
library cache contention
In your example for each submitted job there will be a hard parse due to different procedure arguments.

So, i am now thinking on workaround like

create table job_parameters(job number, arg1 varchar2(30)) tablespace users;
alter table job_parameters add constraint job_parameters$pk primary key(job) using index tablespace users;


create or replace procedure myproc is
j number;
a1 varchar2(30);
begin
j:= sys_context('USERENV','BG_JOB_ID');
select arg1 into a1 from job_parameters where job = j;
/* do something */
delete from job_parameters where job = j;
commit;
end;
/

-- example of submiting the job
declare
j number;
begin
dbms_job.submit(j, what => 'myproc;', next_date => sysdate);
insert into job_parameters values (j,'abc');
commit;
end;
/



More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library