DBA Data[Home] [Help]

PACKAGE BODY: APPS.AD_ZD_PARALLEL_EXEC

Source


1 PACKAGE BODY AD_ZD_PARALLEL_EXEC as
2 /* $Header: ADZDPEXB.pls 120.33.12020000.7 2013/05/21 08:52:29 seetsing ship $ */
3 
4 
5 /******************************************************************
6 
7           Private APIs (Not defined in SPEC )
8 
9 *******************************************************************/
10 
11 -- log shortcut
12 procedure LOG(X_MODULE varchar2, X_LEVEL varchar2, X_MESSAGE varchar2) is
13 begin
14   ad_zd.log(x_module, x_level, x_message);
15 end;
16 
17 -- error shortcut
18 procedure ERROR(X_MODULE varchar2, X_MESSAGE varchar2) is
19 begin
20   ad_zd.error(x_module, x_message);
21 end;
22 
23 -- exec shortcut
24 procedure EXEC(X_SQL in varchar2, X_LOG_MOD in varchar2, X_IGNORE in boolean default false) is
25 begin
26   ad_zd.exec(x_sql, x_log_mod, x_ignore);
27 end;
28 
29 
30 
31 /*
32 ** execute dynamic SQL statement
33 **   x_sql     - statement to execute
34 **   x_log_mod - calling module (for logging)
35 **   x_ignore  - ignore errors
36 */
37 procedure EXEC(
38   X_SQL          in clob,
39   X_EDITION_NAME in varchar2,
40   X_LOG_MOD      in varchar2,
41   X_IGNORE       in boolean default false)
42 is
43   L_CUR integer;
44   L_RET integer;
45 begin
46 
47   --log(x_log_mod, 'STATEMENT', 'SQL(CLOB): '||dbms_lob.substr(x_sql, 3900));
48 
49   l_cur :=  dbms_sql.open_cursor(security_level=>2);
50   dbms_sql.parse(l_cur, x_sql, dbms_sql.native, x_edition_name, null, false);
51   l_ret := dbms_sql.execute(l_cur);
52   dbms_sql.close_cursor(l_cur);
53   commit;
54 
55 exception
56 
57   when others then
58     if dbms_sql.is_open(l_cur) then
59       dbms_sql.close_cursor(l_cur);
60     end if;
61     if x_ignore then
62       log(x_log_mod, 'STATEMENT', 'Ignored: '||SQLERRM);
63     else
64       log(x_log_mod, 'ERROR', 'ERROR: '||SQLERRM);
65       raise;
66     end if;
67 
68 end exec;
69 
70 --
71 -- Checks if given SQL is already exist?
72 function IS_DUPLICATE(X_PHASE    varchar2,
73                       X_SQL_LOB  clob) return varchar2
74 is
75   L_EXIST varchar2(1);
76 begin
77 
78   select 'Y' into l_exist from dual
79   where exists
80          ( select  null
81            from   ad_zd_ddl_handler
82            where  phase = x_phase
83            and    dbms_lob.compare(sql_lob, x_sql_lob) = 0
84            and    nvl(executed, 'N') <> 'S' );
85   return 'Y';
86 
87 exception
88   when no_data_found then
89     return 'N';
90 
91 end IS_DUPLICATE;
92 
93 
94 --
95 -- Procedure to generate next batch id
96 --
97 FUNCTION GET_NEXT_DDL_ID RETURN NUMBER as
98 begin
99   return ad_zd_ddl_handler_ddl_s.nextval;
100 end GET_NEXT_DDL_ID;
101 
102 
103 
104 
105 /********************************************************************
106 
107           Utility Functions / Procedures
108 
109 *********************************************************************/
110 
111 
112 -- Returns the count of failed jobs.
113 --
114 -- If PHASE not supplied, it returns ALL failed jobs
115 -- TODO: This does not make sense, remove autoskip stuff
116 function GETFAILED_JOBS( X_PHASE VARCHAR2)  return number
117 is
118   L_FAILED_COUNT pls_integer;
119 begin
120 
121   -- 1. Check failed (FATAL, ERROR, RUNNING) count.
122   select count(1) into l_failed_count
123   from  ad_zd_ddl_handler
124   where (x_phase is null or phase = x_phase)
125     and executed in (c_job_status_failed, c_job_status_running)
126     and nvl(status, 'ERROR') <> c_job_status_warning_desc;
127 
128   return l_failed_count;
129 end GETFAILED_JOBS;
130 
131 
132 -- Get status of a stored DDL.
133 -- TODO: remove, not needed
134 function GET_STATUS(X_DDL_ID in number) return varchar2
135 is
136   L_STATUS varchar2(1) := 'S';
137 begin
138   select executed into l_status
139   from   ad_zd_ddl_handler
140   where ddl_id = x_ddl_id;
141 
142   return l_status;
143 exception
144   when no_data_found then
145     return l_status;
146 end GET_STATUS;
147 
148 
149 -- This function return the index of the phase ORDER.
150 function GET_PHASE_ORDER(X_PHASE varchar2) return number
151 is
152 begin
153 
154   return
155     ( case x_phase
156         when C_PHASE_DROP_UNUSED_OBJECT then 1
157         when C_PHASE_COPY_TYPE          then 2
158         when C_PHASE_COMPILE_TYPE       then 3
159         when C_PHASE_COPY_EVOLVED_TYPE  then 4
160         when C_PHASE_FIX_COLUMN         then 5
161         when C_PHASE_FIX_TYPE           then 6
162         when C_PHASE_FIX_PUBLIC_SYNONYM then 7
163         when C_PHASE_RECREATE_AQ_OBJECT then 8
164         when C_PHASE_DROP_OBJECT        then 9
165         when C_PHASE_ENABLE_EDITIONING  then 10
166         when C_PHASE_UPGRADE_TABLE      then 11
167         when C_PHASE_UPGRADE_SEED       then 12
168         when C_PHASE_COLLECT_STATS      then 13
169         when C_PHASE_UPGRADE_MVIEW      then 14
170         else 0
171       end );
172 
173 end GET_PHASE_ORDER;
174 
175 
176 -- Returns the count of not_executed or running jobs
177 -- If PHASE not supplied, it returns ALL not-executed jobs
178 function GET_NOT_EXECUTED_JOBS(X_PHASE VARCHAR2)  return number
179 is
180   L_NOT_EXECUTED_COUNT pls_integer;
181 begin
182   select count(1) into l_not_executed_count
183   from  ad_zd_ddl_handler
184   where (x_phase is null or phase = x_phase)
185     and executed in (c_job_status_not_executed, c_job_status_running);
186 
187   return l_not_executed_count;
188 end GET_NOT_EXECUTED_JOBS;
189 
190 
191 -- Updates DDL job status from I or R to N
192 -- Used when restarting a phase
193 procedure UPDATE_STATUS_R_TO_N(X_PHASE  varchar2)
194 is
195   C_MODULE varchar2(127) := c_package||'update_status_r_to_n';
196 begin
197   log(c_module, 'EVENT', 'Reset jobs from R (running) to N (not executed) for phase '||x_phase);
198 
199   update ad_zd_ddl_handler
200     set  executed  = c_job_status_not_executed,
201          execution_time = null
202   where (x_phase is null or phase= x_phase)
203     and executed = c_job_status_running;
204   commit;
205 end UPDATE_STATUS_R_TO_N;
206 
207 
208 --
209 -- Procedure to recompile INVALID objects
210 --
211 procedure RECOMPILE_OBJECTS
212 is
213   C_MODULE varchar2(80) := c_package||'recompile_objects';
214 begin
215   for obj in
216     ( select owner, object_name
217       from   dba_invalid_objects
218       where  object_name like 'AD_ZD%'
219         and  object_type like 'PACKAGE%' )
220   loop
221     log(c_module, 'STATEMENT', 'Recompiling '||obj.owner||'.'||obj.object_name);
222     exec('ALTER PACKAGE '||obj.owner||'.'||obj.object_name||' COMPILE BODY', c_module, true);
223   end loop;
224 end recompile_objects;
225 
226 
227 -- Update job status
228 procedure UPDATEJOB_STATUS(
229   X_DDL_ID   number,
230   X_EXECUTED varchar2,
231   X_STATUS   varchar2,
232   X_ERROR    CLOB)
233 is
234   C_MODULE varchar2(127) := c_package||'updatejob_status';
235 begin
236   update ad_zd_ddl_handler
237     set  executed = x_executed,
238          status = nvl(x_status, c_job_status_success_desc),
239          execution_time =current_timestamp,
240          error = x_error
241   where ddl_id=x_ddl_id;
242 end UPDATEJOB_STATUS;
243 
244 
245 -- Return Error level based on error code
246 --   'WARNING'  - ignorable error
247 --   'ERROR'    - real error, attention required
248 --   'FATAL'    - unexpected error, processing must exit
249 function GET_ERROR_LEVEL(X_ERROR_CODE number, X_MESSAGE varchar2) return varchar2
250 is
251 begin
252 
253   -- Special handling for 942: table or view does not exist
254   -- other than DROP statement, return as ERROR
255   if (x_error_code= -00942 and x_message is not null and
256       not (instr(x_message, 'DROP TABLE') > 0  or instr(x_message, 'DROP VIEW')>0) ) then
257     return c_job_status_error_desc;
258   end if;
259 
260   return
261     ( case x_error_code
262         when -00942 then c_job_status_warning_desc /* table or view does not exist */
263         when -01031 then c_job_status_warning_desc /* Insufficient Privileges */
264         when -04043 then c_job_status_warning_desc /* object ... does not exist */
265         when -24344 then c_job_status_warning_desc /* success_with_compile_err  */
266 
267         when -00600 then c_job_status_fatal_desc   /* Internal error code */
268         when -01013 then c_job_status_fatal_desc   /* User cancel */
269         when -01652 then c_job_status_fatal_desc   /* Unable to extend temp segment */
270         when -01653 then c_job_status_fatal_desc   /* unable to extend table ... in tablespace ... */
271         when -01654 then c_job_status_fatal_desc   /* unable to extend index ... in tablespace ... */
272         when -03113 then c_job_status_fatal_desc   /* end-of-file on communication channel: */
273         when -04030 then c_job_status_fatal_desc   /* out of process memory */
274 	when -04031 then c_job_status_fatal_desc   /* unable to allocate ... bytes of shared memory */
275 	when -07445 then c_job_status_fatal_desc   /* exception encountered: core dump */
276         when -20978 then c_job_status_fatal_desc   /* Cannot drop a type with table dependents, EQ to ORA- */
277 
278         else c_job_status_error_desc
279       end );
280 
281 end GET_ERROR_LEVEL;
282 
283 
284 
285 
286 /******************************************************************
287 
288           Processing APIs
289 
290 *******************************************************************/
291 -- Loads a SQL into AD_ZD_DDL_HANDLER
292 --   X_PHASE : Phase of SQL
293 --   X_SQL   : SQL or PL/SQL block
294 --   X_UNIQUE: If SQL should be checked for uniqueness within the given phase
295 --
296 -- NOTE: Currently this API does not validate if given "phase" is
297 --       a VALID phase or not.
298 PROCEDURE LOAD(
299     X_PHASE   varchar2,
300     X_SQL     clob,
301     X_UNIQUE  boolean default false)
302 is
303   C_MODULE        varchar2(127) := c_package||'load';
304   L_DDL_ID number;
305 begin
306 
307   if (X_SQL is null or x_phase is null) then
308     error(c_module, 'Phase and SQL cannot be null');
309     return;
310   end if;
311 
312   -- Supplied SQL should be checked for uniqueness?
313   if(x_unique) then
314     -- If already exists then don't do any thing.
315     if(is_duplicate(x_phase, x_sql) = 'Y' ) then
316       log(c_module, 'STATEMENT', 'SQL already exists, ignoring duplicate');
317       return;
318     end if;
319   end if;
320 
321   -- If here, this SQL needs to be inserted.
322   l_ddl_id := get_next_ddl_id;
323 
324   insert into ad_zd_ddl_handler(
325     phase          ,
326     ddl_id         ,
327     sql_lob        ,
328     executed       ,
329     status         ,
330     error          ,
331     edition_name   ,
332     execution_time)
333   values(
334     x_phase,
335     l_ddl_id,
336     x_sql,
337     c_job_status_not_executed,
338     c_job_status_not_exec_desc,
339     null,
340     null,
341     null);
342 
343   commit;
344 end LOAD;
345 
346 
347 
348 -- Delete from AD_ZD_DDL_HANDLER
349 PROCEDURE CLEANUP(X_PHASE  varchar2)
350 is
351   C_MODULE        varchar2(127) := c_package||'cleanup';
352 begin
353   log(c_module, 'STATEMENT', 'Cleanup DDL handler, phase='||nvl(x_phase, 'ALL'));
354 
355   delete from ad_zd_ddl_handler
356   where ( x_phase is null or phase =x_phase );
357   commit;
358 
359 end CLEANUP;
360 
361 
362 -- Parallel Execute Worker - execute DDLs from ad_zd_ddl_handler table
363 --
364 --   X_PHASE          - phase of work to select and execute
365 --   X_MAX_WORKERS    - total number of parallel workers
366 --   X_CURRENT_WORKER - worker number for this thread [1..X_MAX_WORKERS]
367 --   X_STATUS         - unused, pass null for now
368 --
369 -- Note: work is evenly distributed across parallel workers by rownumber
370 procedure EXECUTE(
371   X_PHASE          varchar2,
372   X_MAX_WORKERS    number,
373   X_CURRENT_WORKER number,
374   X_MODE           varchar2)
375 is
376   C_MODULE        varchar2(127) := c_package||'execute';
377   L_WORKER_HDR    varchar2(127) :=  '['||x_phase||' '||x_max_workers||':'||x_current_worker||'] ';
378   L_JOB_HDR       varchar2(250);
379   L_ROWCOUNT      integer;
380   L_CUR           integer;
381   L_RET           number;
382   L_ERROR         clob := null;
383 
384   -- Store temporary sub string from SQL_LOB to find DDL keywords
385   L_SQL_SUBSTR    varchar2(1024);
386   L_LONG_ERROR    varchar2(1024);
387   L_ERROR_LEVEL   varchar2(30);
388 
389   cursor C_JOBS(P_PHASE varchar2)  is
390     select mod((rownum-1), x_max_workers)+1 worker_id,
391            row_id, ddl_id, sql_lob, edition_name, executed
392     from
393       ( select rowid row_id, ddl_id, sql_lob, edition_name, executed
394         from   ad_zd_ddl_handler
395         where  phase=p_phase
396         order by ddl_id );
397 
398 begin
399 
400   log(c_module, 'PROCEDURE', l_worker_hdr||'begin');
401 
402   dbms_application_info.set_module('AD_ZD', x_phase);
403 
404   -- Open cursor
405   l_cur := dbms_sql.open_cursor;
406 
407   -- Loop over Jobs
408   for job in c_jobs(x_phase) loop
409     -- if job needs to be executed
410     if (job.worker_id = x_current_worker and job.executed <> c_job_status_succeeded) then
411       begin
412         l_error   := null;
413         l_job_hdr := l_worker_hdr||'ddl_id='||job.ddl_id||'] ';
414         l_job_hdr := '['||x_phase||' '||x_max_workers||':'||x_current_worker||' ddl_id='||job.ddl_id||'] ';
415 
416         -- If job still needs to be executed, mark it as running;
417         update ad_zd_ddl_handler
418           set  executed = c_job_status_running
419             ,  status = c_job_status_running_desc
420             ,  execution_time = current_timestamp
421             ,  error = NULL
422         where rowid = job.row_id
423           and executed not in (c_job_status_running, c_job_status_succeeded);
424 
425         l_rowcount := sql%rowcount;
426         commit;
427 
428         -- If job did not need to be executed, skip to next job
429         if l_rowcount = 0 then
430           log(c_module, 'STATEMENT', l_job_hdr||'Skipping already executed row');
431           continue;
432         end if;
433 
434         -- Execute Job
435         sys.dbms_sql.parse(l_cur, job.sql_lob, dbms_sql.native, job.edition_name, null, false);
436         -- Note: explicit execute required for non-DDL statements
437         -- TODO: gross
438         l_sql_substr := upper(dbms_lob.substr(job.sql_lob, 10, 1));
439         if (l_sql_substr is not null and not
440                (instr(l_sql_substr, 'CREATE ')   > 0 OR
441                 instr(l_sql_substr, 'DROP ')     > 0 OR
442                 instr(l_sql_substr, 'ALTER ')    > 0 OR
443                 instr(l_sql_substr, 'TRUNCATE ') > 0 OR
444                 instr(l_sql_substr, 'RENAME ')   > 0 )) then
445           l_ret := sys.dbms_sql.execute(l_cur);
446         end if;
447 
448         -- record success
449         update ad_zd_ddl_handler
450           set  executed = c_job_status_succeeded
451             ,  status = c_job_status_success_desc
452             ,  execution_time = current_timestamp
453             ,  error = NULL
454         where rowid = job.row_id;
455         commit;
456 
457       exception
458         when others then
459           l_error := sqlerrm;
460           l_long_error := dbms_lob.substr(l_error, 200, 1)
461                             ||' SQL: '||dbms_lob.substr(job.sql_lob, 200, 1);
462 
463           <<error_handler>>
464           case
465             -- If FATAL error, exit worker
466             when (get_error_level(sqlcode)=c_job_status_fatal_desc) then
467               updatejob_status(job.ddl_id, c_job_status_failed, c_job_status_fatal_desc, l_error);
468               error(c_module, l_job_hdr||'Fatal Error, exiting.  '||l_long_error);
469 
470             -- If AD_ZD packages are invalid, exit worker
471             when (sqlcode= -04061  and
472                   (instr(l_error, 'AD_ZD_TABLE' )  > 0 OR
473                    instr(l_error, 'AD_ZD_MVIEW' )  > 0 OR
474                    instr(l_error, 'AD_ZD_PREP' )   > 0 OR
475                    instr(l_error, 'AD_ZD_SEED' )   > 0 OR
476                    instr(l_error, 'AD_ZD_LOG' )    > 0 )) then
477               updatejob_status(job.ddl_id, c_job_status_failed, c_job_status_fatal_desc, l_error);
478               error(c_module, l_job_hdr||'AD_ZD Packages Invalid, exiting.  '||l_long_error);
479 
480             -- mark Job as errored and continue
481             else
482               l_error_level := get_error_level(sqlcode, l_error);
483               if (l_error_level = c_job_status_warning_desc) then
484                 -- treat warning as success, but record warning message
485                 log(c_module, 'STATEMENT', l_job_hdr||'Ignored: '||l_long_error);
486                 updatejob_status(job.ddl_id, c_job_status_succeeded, c_job_status_success_desc, l_error);
487               else
488                 -- record error status and message
489                 log(c_module, 'ERROR', l_job_hdr||l_long_error);
490                 updatejob_status(job.ddl_id, c_job_status_failed, l_error_level, l_error);
491               end if;
492 
493           end case error_handler;
494           commit;
495       end;
496     end if; /* Job needs to be executed */
497   end loop; /* Job Loop */
498 
499   commit;
500   if dbms_sql.is_open(l_cur) then
501     dbms_sql.close_cursor(l_cur);
502   end if;
503   log(c_module, 'PROCEDURE', l_worker_hdr||'end' );
504 
505 exception
506   when others then
507     if dbms_sql.is_open(l_cur) then
508       dbms_sql.close_cursor(l_cur);
509     end if;
510     raise;
511 end EXECUTE;
512 
513 end AD_ZD_PARALLEL_EXEC;