1 package body ad_invoker as
2 /* $Header: adinvspb.pls 120.0 2005/05/25 11:49:07 appldev noship $ */
3
4 --
5 -- Global private SQL cursors
6 --
7
8 cursor REWRITE_NOT_INCR is
9 select /*+ ORDERED */
10 u.name owner, o.name object_name,
11 decode(o.type#, 7, 'PROCEDURE', 8, 'FUNCTION', 9, 'PACKAGE', '??')
12 object_type
13 from fnd_oracle_userid fou, sys.user$ u, sys.obj$ o, sys.procedure$ p
14 where fou.read_only_flag = 'U'
15 and fou.install_group_num = 1
16 and u.name = fou.oracle_username
17 and o.owner# = u.user#
18 and o.type# in (7, 8, 9)
19 and o.name not in ('APPS_DDL', 'APPS_ARRAY_DDL')
20 and o.obj# = p.obj#
21 and bitand(p.options, 16) <> 16;
22
23 cursor REWRITE_INCR is
24 select /*+ FULL(o), ORDERED */
25 u.name owner, o.name object_name,
26 decode(o.type#, 7, 'PROCEDURE', 8, 'FUNCTION', 9, 'PACKAGE', '??')
27 object_type
28 from sys.obj$ o, ad_timestamps t, fnd_oracle_userid fou, sys.user$ u,
29 sys.procedure$ p
30 where fou.read_only_flag = 'U'
31 and fou.install_group_num = 1
32 and u.name = fou.oracle_username
33 and o.owner# = u.user#
34 and o.type# in (7, 8, 9)
35 and o.name not in ('APPS_DDL', 'APPS_ARRAY_DDL')
36 and o.obj# = p.obj#
37 and bitand(p.options, 16) <> 16
38 and t.type = 'Invoker Maintenance'
39 and t.attribute = 'Last Run'
40 and o.mtime >= t.timestamp;
41
42 cursor GRANTS_NOT_INCR is
43 select do.owner, do.object_name, do.object_type, u.oracle_username
44 from dba_objects do, fnd_oracle_userid u
45 where do.owner =
46 (select o.oracle_username
47 from fnd_oracle_userid o
48 where o.read_only_flag = 'U'
49 and o.install_group_num = 1)
50 and do.object_type in ('PACKAGE', 'PROCEDURE', 'FUNCTION',
51 'JAVA CLASS')
52 and do.object_name not in ('APPS_DDL', 'APPS_ARRAY_DDL')
53 and u.read_only_flag = 'U'
54 and u.install_group_num > 1;
55
56 cursor GRANTS_INCR is
57 select do.owner, do.object_name, do.object_type, u.oracle_username
58 from dba_objects do, fnd_oracle_userid u, ad_timestamps t
59 where do.owner =
60 (select o.oracle_username
61 from fnd_oracle_userid o
62 where o.read_only_flag = 'U'
63 and o.install_group_num = 1)
64 and do.object_type in ('PACKAGE', 'PROCEDURE', 'FUNCTION',
65 'JAVA CLASS')
66 and do.object_name not in ('APPS_DDL', 'APPS_ARRAY_DDL')
67 and u.read_only_flag = 'U'
68 and u.install_group_num > 1
69 and t.type = 'Invoker Maintenance'
70 and t.attribute = 'Last Run'
71 and do.last_ddl_time >= t.timestamp;
72
73 cursor MRC_GRANTS_OBJ_ID (c_apps_schema in varchar2) is
74 select do.owner, do.object_name, do.object_type
75 from dba_objects do
76 where do.owner = upper(c_apps_schema)
77 and do.object_type in ('PACKAGE', 'PROCEDURE', 'FUNCTION',
78 'JAVA CLASS')
79 and do.object_name not in ('APPS_DDL', 'APPS_ARRAY_DDL')
80 and do.object_name not like 'FFP%';
81
82 -- Private data types
83
84 type rowid_list is table of rowid index by binary_integer;
85
86 type integer_list is table of integer index by binary_integer;
87
88 type owner_list_t is table of varchar2(30) index by binary_integer;
89
90 type object_name_list_t is table of varchar2(128) index by binary_integer;
91
92 type object_type_list_t is table of varchar2(18) index by binary_integer;
93
94 --
95 -- Procedures and Functions
96 --
97
98 procedure get_rewrite_pkgs
99 (is_incremental in varchar2)
100 --
101 -- Loads the AD_INVOKER_TASKS table with the list of packages,
102 -- procedures, and functions in the first APPS schema that need to
103 -- be re-written for Invoker's Rights
104 --
105 -- is_incremental can be either
106 -- 'TRUE' - only process PL/SQL objects that have changed since last run
107 -- 'FALSE' - process all applicable PL/SQL objects
108 --
109 -- If for some reason the row for 'Invoker Maintenance', 'Last Run'
110 -- is missing from AD_TIMESTAMPS, get_rewrite_pkgs() will fail in
111 -- incremental mode. This can be fixed by running the whole
112 -- Invoker's Rights processing logic in non-incremental mode
113 -- (via adadmin "Compile APPS Schema(s)")
114 --
115 is
116 found_authid varchar2(10);
117 invoker_flag varchar2(10);
118 begin
119 ad_apps_private.error_buf := null;
120 --
121 -- Insert rows into ad_invoker_tasks for all packages, procedures, and
122 -- functions that do not contain the 'AUTHID' keyword
123 --
124 -- Only look in the first APPS schema.
125 --
126
127 if is_incremental = 'FALSE' then
128
129 for c1 in REWRITE_NOT_INCR loop
130
131 classify_plsql_object(c1.owner, c1.object_name, c1.object_type,
132 found_authid, invoker_flag);
133
134 if found_authid = 'FALSE' then
135
136 insert into ad_invoker_tasks (
137 phase, owner, name, type, other_schema,
138 worker, done_flag, authid_flag, invoker_flag, boundary_flag)
139 values (
140 1, c1.owner, c1.object_name, c1.object_type, c1.owner,
141 0, 'N', null, null, 'N');
142
143 end if;
144 -- end if no AUTHID keyword found -> needs rewrite
145
146 end loop;
147 -- end loop through PL/SQL specification objects in first APPS schema
148
149 elsif is_incremental = 'TRUE' then
150
151 for c1 in REWRITE_INCR loop
152
153 classify_plsql_object(c1.owner, c1.object_name, c1.object_type,
154 found_authid, invoker_flag);
155
156 if found_authid = 'FALSE' then
157
158 insert into ad_invoker_tasks (
159 phase, owner, name, type, other_schema,
160 worker, done_flag, authid_flag, invoker_flag, boundary_flag)
161 values (
162 1, c1.owner, c1.object_name, c1.object_type, c1.owner,
163 0, 'N', null, null, 'N');
164
165 end if;
166 -- end if no AUTHID keyword found -> needs rewrite
167
168 end loop;
169 -- end loop through PL/SQL specification objects in first APPS schema
170 -- that have changed since the last run
171
172 else
173 raise_application_error(-20000,
174 'is_incremental must be either TRUE or FALSE');
175 end if;
176
177 exception
178 when others then
179 ad_apps_private.error_buf := 'get_rewrite_pkgs(): '||
180 ad_apps_private.error_buf;
181 raise;
182 end get_rewrite_pkgs;
183
184
185 procedure add_phase_boundary
186 (num_workers in integer)
187 --
188 -- Loads the AD_INVOKER_TASKS table with a phase boundary,
189 -- which consists of one row per worker with the boundary_flag set
190 --
191 is
192 num_workers_local pls_integer;
193 counter pls_integer;
194 statement varchar2(300);
195 begin
196 ad_apps_private.error_buf := null;
197 --
198 -- Insert a phase boundary
199 -- (actually a new phase with one row per worker)
200 --
201
202 -- Actual length: 225
203
204 statement :=
205 'insert into ad_invoker_tasks ('||
206 'phase, owner, name, type, other_schema,'||
207 'worker, done_flag, authid_flag, invoker_flag, boundary_flag)'||
208 'values ('||
209 '2, ''Boundary'', ''Boundary'', ''Boundary'', to_char(:wrk_num),'||
210 ':wrk_num, ''N'', null, null, ''Y'')';
211
212 for counter in 1..num_workers loop
213
214 EXECUTE IMMEDIATE statement
215 using counter, counter;
216
217 end loop;
218
219 exception
220 when others then
221 ad_apps_private.error_buf := 'add_phase_boundary('||
222 num_workers||'): '||
223 ad_apps_private.error_buf;
224 raise;
225 end add_phase_boundary;
226
227
228 procedure get_grant_pkgs
229 (is_incremental in varchar2)
230 --
231 -- Loads the AD_INVOKER_TASKS table with the list of packages,
232 -- procedures, functions and Java objects in the first APPS schema
233 -- in a cross product with all of the other APPS schemas.
234 -- Will have to verify the grants/synonyms for each combination of
235 -- first and (2-N)th APPS schemas
236 --
237 -- is_incremental can be either
238 -- 'TRUE' - only process objects that have changed since last run
239 -- 'FALSE' - process all applicable objects
240 --
241 -- If for some reason the row for 'Invoker Maintenance', 'Last Run'
242 -- is missing from AD_TIMESTAMPS, get_grant_pkgs() will fail in
243 -- incremental mode. This can be fixed by running the whole
244 -- Invoker's Rights processing logic in non-incremental mode
245 -- (via adadmin "Compile APPS Schema(s)")
246 --
247 is
248 begin
249 ad_apps_private.error_buf := null;
250 --
251 -- Create rows for each grant task. Insert some data so later updates
252 -- can't cause row chaining.
253 --
254 -- If only one APPS schema, no rows are returned
255 --
256 -- Will update the rows later as follows:
257 --
258 -- authid_flag=N, invoker_flag=null
259 -- if no AUTHID keyword in PL/SQL object source
260 --
261 -- authid_flag=Y, invoker_flag=D
262 -- if AUTHID DEFINER in PL/SQL object source
263 --
264 -- authid_flag=Y, invoker_flag=I
265 -- if AUTHID CURRENT_USER in PL/SQL object source
266 --
267
268 if is_incremental = 'FALSE' then
269
270 for c1 in GRANTS_NOT_INCR loop
271
272 insert into ad_invoker_tasks (
273 phase, owner, name, type, other_schema,
274 worker, done_flag, authid_flag, invoker_flag, boundary_flag)
275 values (
276 3, c1.owner, c1.object_name, c1.object_type, c1.oracle_username,
277 0, 'N', 'X', 'X', 'N');
278
279 end loop;
280 -- end loop through PL/SQL specification objects in first APPS schema
281
282 elsif is_incremental = 'TRUE' then
283
284 for c1 in GRANTS_INCR loop
285
286 insert into ad_invoker_tasks (
287 phase, owner, name, type, other_schema,
288 worker, done_flag, authid_flag, invoker_flag, boundary_flag)
289 values (
290 3, c1.owner, c1.object_name, c1.object_type, c1.oracle_username,
291 0, 'N', 'X', 'X', 'N');
292
293 end loop;
294 -- end loop through PL/SQL specification objects in first APPS schema
295 -- that have changed since the last run
296
297 else
298 raise_application_error(-20000,
299 'is_incremental must be either TRUE or FALSE');
300 end if;
301
302 exception
303 when others then
304 ad_apps_private.error_buf := 'get_grant_pkgs(): '||
305 ad_apps_private.error_buf;
306 raise;
307 end get_grant_pkgs;
308
309
310 procedure invoker_maint_serial
311 (is_incremental in varchar2)
312 --
313 -- Runs the whole Invoker's Rights maintenance logic in serial
314 --
315 -- Does not log errors to a table: just fails if encounters errors
316 --
317 -- The parallel version is strongly recommended over this version
318 -- (just use this from AutoPatch in serial mode)
319 --
320 is
321 found_authid varchar2(10);
322 invoker_flag varchar2(10);
323 begin
324 --
325 -- Clear error buffer
326 --
327
328 ad_apps_private.error_buf := null;
329
330 --
331 -- Run rewrite logic
332 --
333
334 if is_incremental = 'FALSE' then
335
336 for c1 in REWRITE_NOT_INCR loop
337
338 classify_plsql_object(c1.owner, c1.object_name, c1.object_type,
339 found_authid, invoker_flag);
340
341 if found_authid = 'FALSE' then
342
343 rewrite_a_package(c1.owner, c1.object_name, c1.object_type,
344 c1.owner, 'FALSE');
345
346 end if;
347 -- end if no AUTHID keyword found -> needs rewrite
348
349 end loop;
350 -- end loop through PL/SQL specification objects in first APPS schema
351
352 elsif is_incremental = 'TRUE' then
353
354 for c1 in REWRITE_INCR loop
355
356 classify_plsql_object(c1.owner, c1.object_name, c1.object_type,
357 found_authid, invoker_flag);
358
359 if found_authid = 'FALSE' then
360
361 rewrite_a_package(c1.owner, c1.object_name, c1.object_type,
362 c1.owner, 'FALSE');
363
364 end if;
365 -- end if no AUTHID keyword found -> needs rewrite
366
367 end loop;
368 -- end loop through PL/SQL specification objects in first APPS schema
369 -- that have changed since the last run
370
371 else
372 raise_application_error(-20000,
373 'is_incremental must be either TRUE or FALSE [1]');
374 end if;
375
376 --
377 -- Run grant logic
378 --
379
380 if is_incremental = 'FALSE' then
381
382 for c1 in GRANTS_NOT_INCR loop
383
384 if (c1.object_type not like 'JAVA%') then
385
386 classify_plsql_object(c1.owner, c1.object_name, c1.object_type,
387 found_authid, invoker_flag);
388
389 if found_authid = 'FALSE' then
390
391 grant_a_package(c1.owner, c1.object_name, c1.object_type,
392 c1.oracle_username, 'N', null, 'FALSE');
393
394 else
395
396 grant_a_package(c1.owner, c1.object_name, c1.object_type,
397 c1.oracle_username, 'Y', invoker_flag, 'FALSE');
398
399 end if;
400 -- end if no AUTHID keyword found
401 else
402 grant_a_java_object(c1.owner, c1.object_name, c1.object_type,
403 c1.oracle_username, 'FALSE');
404 end if;
405
406 end loop;
407 -- end loop through PL/SQL specification objects in first APPS schema
408
409 elsif is_incremental = 'TRUE' then
410
411 for c1 in GRANTS_INCR loop
412
413 if (c1.object_type not like 'JAVA%') then
414
415 classify_plsql_object(c1.owner, c1.object_name, c1.object_type,
416 found_authid, invoker_flag);
417
418 if found_authid = 'FALSE' then
419
420 grant_a_package(c1.owner, c1.object_name, c1.object_type,
421 c1.oracle_username, 'N', null, 'FALSE');
422
423 else
424
425 grant_a_package(c1.owner, c1.object_name, c1.object_type,
426 c1.oracle_username, 'Y', invoker_flag, 'FALSE');
427
428 end if;
429 -- end if no AUTHID keyword found
430 else
431 grant_a_java_object(c1.owner, c1.object_name, c1.object_type,
432 c1.oracle_username, 'FALSE');
433 end if;
434 end loop;
435 -- end loop through PL/SQL specification objects in first APPS schema
436 -- that have changed since the last run
437
438 else
439 raise_application_error(-20000,
440 'is_incremental must be either TRUE or FALSE [2]');
441 end if;
442
443 --
444 -- Update timestamp
445 --
446
447 update_timestamp('Invoker Maintenance','Last Run');
448
449 exception
450 when others then
451 ad_apps_private.error_buf := 'invoker_maint_serial('||
452 is_incremental || '): '||
453 ad_apps_private.error_buf;
454 raise;
455 end invoker_maint_serial;
456
457
458 procedure invoker_mrc_grants
459 (apps_schema in varchar2,
460 mrc_schema in varchar2)
461 --
462 -- Runs the Invoker's Rights grants logic for MRC/MLS schemas
463 --
464 -- This replaces the non-invoker MRC logic that copies packages, procedures,
465 -- functions, and package bodies
466 --
467 is
468 found_authid varchar2(10);
469 invoker_flag varchar2(10);
470 owner_to_process owner_list_t;
471 object_name_to_process object_name_list_t;
472 object_type_to_process object_type_list_t;
473 row_index binary_integer;
474 row_count binary_integer;
475 the_owner varchar2(30);
476 the_obj_name varchar2(128);
477 the_obj_type varchar2(30);
478 the_mrc_schema varchar2(30);
479 begin
480 --
481 -- Clear error buffer
482 --
483
484 ad_apps_private.error_buf := null;
485
486 -- set variables
487
488 the_mrc_schema := upper(mrc_schema);
489
490 --
491 -- select row set to process into rows_to_process
492 --
493
494 row_index := 1;
495
496 for c1 in MRC_GRANTS_OBJ_ID(apps_schema) loop
497
498 owner_to_process(row_index) := c1.owner;
499 object_name_to_process(row_index) := c1.object_name;
500 object_type_to_process(row_index) := c1.object_type;
501
502 row_index := row_index + 1;
503 end loop;
504
505 -- end loop through PL/SQL specification objects in APPS schema
506
507 row_count := row_index - 1;
508
509 --
510 -- Run grant logic
511 --
512
513 for row_index in 1..row_count loop
514
515 if (object_type_to_process(row_index) not like 'JAVA%') then
516 classify_plsql_object(owner_to_process(row_index),
517 object_name_to_process(row_index),
518 object_type_to_process(row_index),
519 found_authid, invoker_flag);
520
521 if found_authid = 'FALSE' then
522
523 grant_a_package(owner_to_process(row_index),
524 object_name_to_process(row_index),
525 object_type_to_process(row_index),
526 the_mrc_schema, 'N', null, 'FALSE');
527
528 else
529
530 if invoker_flag = 'S' then
531
532 --
533 -- 'S' means this is a definer's rights package with the
534 -- /*nosync*/ comment. For regular APPS schemas, we do not
535 -- copy it. For MRC schemas, we want to treat it just like any
536 -- other definer's rights package: copy it to MRC
537 --
538
539 grant_a_package(owner_to_process(row_index),
540 object_name_to_process(row_index),
541 object_type_to_process(row_index),
542 the_mrc_schema, 'Y', 'D', 'FALSE');
543
544 else
545
546 grant_a_package(owner_to_process(row_index),
547 object_name_to_process(row_index),
548 object_type_to_process(row_index),
549 the_mrc_schema, 'Y', invoker_flag, 'FALSE');
550
551 end if;
552 -- end if invoker_flag = 'S'
553
554 end if;
555 -- end if no AUTHID keyword found
556 else
557 grant_a_java_object(owner_to_process(row_index),
558 object_name_to_process(row_index),
559 object_type_to_process(row_index),
560 the_mrc_schema, 'FALSE');
561 end if;
562
563 end loop;
564 -- end loop through PL/SQL specification objects in APPS schema
565
566 exception
567 when others then
568 ad_apps_private.error_buf := 'invoker_mrc_grants('||
569 apps_schema ||', '|| mrc_schema || '): '||
570 ad_apps_private.error_buf;
571 raise;
572 end invoker_mrc_grants;
573
574
575 procedure calculate_grant_types
576 (worker_num in integer)
577 --
578 -- Sets the authid_flag and invoker_flag for the PL/SQL objects
579 -- that this worker will process.
580 --
581 -- Have to do this in the worker because the grant logic is different
582 -- depending on whether a given package is Invoker's Rights or
583 -- Definer's Rights, and any package that is re-written will change from
584 -- Definer's Rights to Invoker's Rights.
585 --
586 is
587 cursor WORKER_GRANTS is
588 select rowid, owner, name, type
589 from ad_invoker_tasks
590 where phase = 3
591 and type not like 'JAVA%'
592 and worker = calculate_grant_types.worker_num;
593 found_authid varchar2(10);
594 invoker_flag varchar2(10);
595 begin
596 for c1 in WORKER_GRANTS loop
597
598 classify_plsql_object(c1.owner, c1.name, c1.type,
599 found_authid, invoker_flag);
600
601 if found_authid = 'FALSE' then
602
603 update ad_invoker_tasks
604 set authid_flag = 'N',
605 invoker_flag = null
606 where rowid = c1.rowid;
607
608 else
609
610 update ad_invoker_tasks
611 set authid_flag = 'Y',
612 invoker_flag = calculate_grant_types.invoker_flag
613 where rowid = c1.rowid;
614
615 end if;
616 -- end if no AUTHID keyword found
617
618 end loop;
619 -- end loop through grants that this worker will process
620
621 exception
622 when others then
623 ad_apps_private.error_buf := 'calculate_grant_types('||
624 worker_num||'): '||
625 ad_apps_private.error_buf;
626 raise;
627 end calculate_grant_types;
628
629
630 procedure assign_tasks
631 (num_workers in integer)
632 --
633 -- Distribute the tasks evenly among the workers within each phase
634 -- Start each phase with worker 1. Don't update any tasks in the
635 -- phase boundary rows.
636 --
637 is
638 cursor cs1 (phase_num in number) is
639 select rowid
640 from ad_invoker_tasks
641 where phase = phase_num;
642 counter pls_integer;
643 num_workers_local pls_integer;
644 begin
645 ad_apps_private.error_buf := null;
646 num_workers_local := num_workers;
647 --
648 -- Assign tasks for first phase (rewrite PL/SQL)
649 --
650 counter := 1;
651
652 for the_rec in cs1(1) loop
653
654 if mod(counter, num_workers_local + 1) = 0 then
655 counter := 1;
656 end if;
657
658 update ad_invoker_tasks
659 set worker = counter
660 where rowid = the_rec.rowid;
661
662 counter := counter + 1;
663
664 end loop;
665
666 --
667 -- Don't do anything to the second phase
668 -- (which actually serves as the phase boundary for the first phase)
669 --
670
671 --
672 -- Assign tasks for third phase (Do PL/SQL grants/synonyms)
673 --
674 counter := 1;
675
676 for the_rec in cs1(3) loop
677
678 if mod(counter, num_workers_local + 1) = 0 then
679 counter := 1;
680 end if;
681
682 update ad_invoker_tasks
683 set worker = counter
684 where rowid = the_rec.rowid;
685
686 counter := counter + 1;
687
688 end loop;
689
690 exception
691 when others then
692 ad_apps_private.error_buf := 'assign_tasks('||
693 num_workers||'): '||
694 ad_apps_private.error_buf;
695 raise;
696 end assign_tasks;
697
698
699 procedure apps_ddl_check
700 --
701 -- Doesn't do anything if no packages to process
702 -- If are packages to process:
703 -- Compiles any invalid APPS*DDL packages in the database
704 -- Checks for APPS_DDL and APPS_ARRAY_DDL packages in all APPS schemas
705 --
706 is
707 cursor ANY_INV_ROWS is
708 select count(*)
709 from ad_invoker_tasks
710 where phase in (1, 3);
711 cursor APPS_SCHEMAS is
712 select oracle_username
713 from fnd_oracle_userid
714 where read_only_flag = 'U';
715 num_rows number;
716 begin
717 --
718 -- Only run this check if we have anything to do
719 -- Otherwise, exit early
720 --
721 open ANY_INV_ROWS;
722
723 fetch ANY_INV_ROWS
724 into num_rows;
725
726 if ANY_INV_ROWS%NOTFOUND then
727 close ANY_INV_ROWS;
728 raise no_data_found;
729 else
730 close ANY_INV_ROWS;
731 end if;
732
733 if num_rows = 0 then
734 return;
735 end if;
736
737 --
738 -- If we got this far, there are rows to process, so we better make sure
739 -- that all of the APPS schemas have the proper APPS*DDL packages
740 --
741
742 -- First compile any invalid APPS*DDL packages in the whole database
743
744 ad_compile.compile_apps_ddl;
745
746 -- Then verify that the APPS*DDL packages in the APPS schemas are OK
747
748 for apps_rec in APPS_SCHEMAS loop
749
750 ad_apps_private.check_for_apps_ddl(apps_rec.oracle_username);
751
752 end loop;
753
754 exception
755 when others then
756 ad_apps_private.error_buf := 'apps_ddl_check(): '||
757 ad_apps_private.error_buf;
758 raise;
759 end apps_ddl_check;
760
761
762 procedure update_done
763 (what_row in rowid)
764 --
765 -- Sets AD_INVOKER_TASKS.DONE_FLAG to 'Y' for this particular row.
766 -- Commits the changes using an autonomous transaction
767 --
768 is
769 PRAGMA AUTONOMOUS_TRANSACTION;
770 begin
771
772 update ad_invoker_tasks
773 set done_flag = 'Y'
774 where rowid = what_row;
775
776 commit;
777
778 exception
779 when others then
780 ad_apps_private.error_buf := 'update_done('||
781 what_row||'): '||
782 ad_apps_private.error_buf;
783 raise;
784 end update_done;
785
786
787 procedure rewrite_pkgs
788 (worker_num in integer)
789 --
790 -- Re-writes the packages assigned to this worker to use
791 -- Invoker's Rights.
792 --
793 is
794 rows_to_process rowid_list;
795 row_index binary_integer;
796 row_count binary_integer;
797 the_owner varchar2(30);
798 obj_name varchar2(128);
799 obj_type varchar2(30);
800 other_schema varchar2(30);
801 is_done varchar2(2);
802 cursor c1 (worker_number in number) is
803 select rowid the_row_id
804 from ad_invoker_tasks
805 where phase = 1
806 and worker = worker_number;
807 cursor c2 (c_row_id in rowid) is
808 select owner, name, type, other_schema, done_flag
809 from ad_invoker_tasks
810 where rowid = c_row_id;
811 begin
812 --
813 -- clear error buffer
814 --
815 ad_apps_private.error_buf := null;
816
817 --
818 -- select row set to process into rows_to_process
819 --
820 row_index := 1;
821 for c1_rec in c1(worker_num) loop
822
823 rows_to_process(row_index) := c1_rec.the_row_id;
824
825 row_index := row_index + 1;
826 end loop;
827
828 row_count := row_index - 1;
829
830 --
831 -- actually process rows
832 --
833 for row_index in 1..row_count loop
834
835 open c2 (rows_to_process(row_index));
836
837 fetch c2
838 into the_owner, obj_name, obj_type, other_schema, is_done;
839
840 if c2%NOTFOUND then
841 close c2;
842 raise no_data_found;
843 end if;
844
845 close c2;
846
847 if nvl(is_done,'N') = 'N' then
848
849 rewrite_a_package(the_owner, obj_name, obj_type, other_schema, 'TRUE');
850
851 update_done(rows_to_process(row_index));
852
853 end if;
854
855 end loop;
856
857 exception
858 when others then
859 ad_apps_private.error_buf := 'rewrite_pkgs('||
860 worker_num||'): '||
861 ad_apps_private.error_buf;
862 raise;
863 end rewrite_pkgs;
864
865
866 procedure rewrite_a_package
867 (owner in varchar2,
868 name in varchar2,
869 type in varchar2,
870 new_owner in varchar2,
871 log_to_table in varchar2)
872 --
873 -- Rewrites a specific package to use Invoker's Rights.
874 --
875 -- if log_to_table is 'TRUE', writes errors to ad_parallel_compile_errors
876 --
877 -- Got most of the logic from ad_apps_private.copy_code
878 --
879 is
880 success_with_comp_error exception;
881 PRAGMA EXCEPTION_INIT(success_with_comp_error, -24344);
882 cursor c1 is
883 select text from dba_source
884 where owner = upper(rewrite_a_package.owner)
885 and name = upper(rewrite_a_package.name)
886 and type = upper(rewrite_a_package.type)
887 order by line;
888 row_count integer;
889 source_line varchar2(255);
890 new_source_line varchar2(300);
891 found_authid boolean;
892 authid_line number;
893 found_is_as boolean;
894 is_as_line number;
895 word_location number;
896 is_as_position number;
897 we_found_it varchar2(10);
898 timestamp varchar2(20);
899 begin
900 -- dbms_output.put_line('rewrite_a_package('
901 -- || owner ||', '|| name ||', '|| type ||', '
902 -- || new_owner || ', '|| log_to_table ||')');
903 -- return;
904
905 -- Validate PL/SQL object type
906
907 if upper(type) <> 'PACKAGE'
908 and upper(type) <> 'PROCEDURE'
909 and upper(type) <> 'FUNCTION' then
910
911 if log_to_table = 'TRUE' then
912
913 timestamp := to_char(sysdate,'YYYY-MM-DD:HH24:MI:SS');
914
915 insert into ad_parallel_compile_errors (
916 owner, worker_number, timestamp, type, text)
917 select upper(owner),
918 0,
919 timestamp,
920 '1 REWRITE ERROR',
921 upper(type)||' '||upper(owner)||'.'||upper(name)||
922 ': Object type "'||upper(type)||'" not supported.'
923 from sys.dual;
924
925 end if;
926 -- end if log errors/messages to ad_parallel_compile_errors
927
928 -- dbms_output.put_line('Do not know how to rewrite objects of type "'||
929 -- upper(type)||'".');
930
931 return;
932
933 end if;
934 -- end if not valid type
935
936 -- Initialize variables
937
938 found_authid := FALSE;
939 found_is_as := FALSE;
940
941 authid_line := 0;
942 is_as_line := 0;
943
944 --
945 -- get the source text
946 -- purposely start counter at 1 as later we add the
947 -- create or replace at line 1
948 --
949 -- parse the text while we're at it
950 --
951 row_count:=1;
952 for c1rec in c1 loop
953 row_count:=row_count+1;
954
955 if not found_is_as then
956
957 -- Check for AS
958
959 word_location := instr(upper(c1rec.text),'AS');
960
961 if word_location <> 0 then
962
963 -- Do more strict checking
964
965 verify_token_location(upper(c1rec.text), 'AS',
966 we_found_it, word_location);
967
968 if we_found_it = 'TRUE' then
969
970 found_is_as := TRUE;
971 is_as_line := row_count - 1;
972 is_as_position := word_location;
973 source_line := c1rec.text;
974
975 end if;
976 -- end if we really found AS
977
978 end if;
979 -- end if found AS using INSTR
980
981 -- Check for IS
982
983 word_location := instr(upper(c1rec.text),'IS');
984
985 if word_location <> 0 then
986
987 -- Do more strict checking
988
989 verify_token_location(upper(c1rec.text), 'IS',
990 we_found_it, word_location);
991
992 if we_found_it = 'TRUE' then
993
994 found_is_as := TRUE;
995 is_as_line := row_count - 1;
996 is_as_position := word_location;
997 source_line := c1rec.text;
998
999 end if;
1000 -- end if we really found IS
1001
1002 end if;
1003 -- end if found IS using INSTR
1004
1005 -- Check for AUTHID, and return if we find it
1006
1007 word_location := instr(upper(c1rec.text),'AUTHID');
1008
1009 if word_location <> 0 then
1010
1011 -- Do more strict checking
1012
1013 verify_token_location(upper(c1rec.text), 'AUTHID',
1014 we_found_it, word_location);
1015
1016 if we_found_it = 'TRUE' then
1017
1018 -- If we found an AUTHID keyword, return
1019
1020 found_authid := TRUE;
1021 authid_line := row_count - 1;
1022
1023 -- dbms_output.put_line('Found AUTHID at line '||authid_line);
1024
1025 if log_to_table = 'TRUE' then
1026
1027 timestamp := to_char(sysdate,'YYYY-MM-DD:HH24:MI:SS');
1028
1029 insert into ad_parallel_compile_errors (
1030 owner, worker_number, timestamp, type, text)
1031 select upper(owner),
1032 0,
1033 timestamp,
1034 '1 REWRITE MESSAGE',
1035 upper(type)||' '||upper(owner)||'.'||upper(name)||
1036 ' contains AUTHID - Not rewritten'
1037 from sys.dual;
1038
1039 end if;
1040 -- end if log errors/messages to ad_parallel_compile_errors
1041
1042 return;
1043
1044 end if;
1045 -- end if we really found AUTHID
1046
1047 end if;
1048 -- end if found AUTHID using INSTR
1049
1050 end if;
1051 -- end parse lines until we find the IS/AS keyword
1052
1053 -- build one line of sql statement in the global variable in
1054 -- the global array variable in to schema.
1055
1056 if (length (c1rec.text) > 255) then
1057
1058 -- text > 255 chars
1059 --
1060 -- log message to error table if requested
1061 -- ignore the error and return success
1062 -- (don't try to rewrite package)
1063 --
1064
1065 if log_to_table = 'TRUE' then
1066
1067 timestamp := to_char(sysdate,'YYYY-MM-DD:HH24:MI:SS');
1068
1069 insert into ad_parallel_compile_errors (
1070 owner, worker_number, timestamp, type, text)
1071 select upper(owner),
1072 0,
1073 timestamp,
1074 '1 REWRITE MESSAGE',
1075 upper(type)||' '||upper(owner)||'.'||upper(name)||
1076 ' contains line(s) > 255 chars - Not rewritten'
1077 from sys.dual;
1078
1079 end if;
1080 -- end if log errors/messages to ad_parallel_compile_errors
1081
1082 return;
1083
1084 else
1085
1086 -- text <= 255 chars
1087 --
1088 -- just add to array of source text lines
1089 --
1090
1091 ad_apps_private.do_array_assignment(rewrite_a_package.new_owner,
1092 c1rec.text, row_count);
1093
1094 end if;
1095 -- end if text <= 255 chars
1096
1097 end loop;
1098 -- end loop to get and parse source text
1099
1100 --
1101 -- Alter the line on which we found the IS|AS
1102 --
1103 -- The parsing above is fairly good, but there are still a
1104 -- few failure cases I can think of (maybe more?):
1105 --
1106 -- 1) it doesn't handle comments
1107 --
1108 -- We will ignore this for now
1109 --
1110 -- 2) if the line is already pretty long, we will fail below if adding
1111 -- AUTHID CURRENT_USER pushes the length past 255
1112 --
1113 -- If the line would be too long, just exit the procedure without
1114 -- rewriting the PL/SQL object. That's probably better than
1115 -- raising an exception. If someone wonders why their PL/SQL
1116 -- object didn't get rewritten, we can always just explain
1117 -- that the rewrite routine doesn't work if the IS/AS keyword
1118 -- is on a long line.
1119 --
1120
1121 if not found_is_as then
1122 --
1123 -- This should never happen
1124 -- If it does, just exit without editing the PL/SQL object
1125 --
1126
1127 -- dbms_output.put_line('No IS/AS keyword found in '||upper(type)||' '||
1128 -- upper(owner)||'.'||upper(name));
1129
1130 if log_to_table = 'TRUE' then
1131
1132 timestamp := to_char(sysdate,'YYYY-MM-DD:HH24:MI:SS');
1133
1134 insert into ad_parallel_compile_errors (
1135 owner, worker_number, timestamp, type, text)
1136 select upper(owner),
1137 0,
1138 timestamp,
1139 '1 REWRITE ERROR',
1140 upper(type)||' '||upper(owner)||'.'||upper(name)||
1141 ' has no IS/AS keyword - Not rewritten'
1142 from sys.dual;
1143
1144 end if;
1145 -- end if log errors/messages to ad_parallel_compile_errors
1146
1147 return;
1148
1149 end if;
1150 -- end if didn't find IS/AS keyword
1151
1152 --
1153 -- Rewrite PL/SQL object
1154 --
1155
1156 new_source_line := substr(source_line,1,is_as_position-1)||
1157 'AUTHID CURRENT_USER '||substr(source_line,is_as_position);
1158
1159 if length(new_source_line) > 255 then
1160
1161 if log_to_table = 'TRUE' then
1162
1163 timestamp := to_char(sysdate,'YYYY-MM-DD:HH24:MI:SS');
1164
1165 insert into ad_parallel_compile_errors (
1166 owner, worker_number, timestamp, type, text)
1167 select upper(owner),
1168 0,
1169 timestamp,
1170 '1 REWRITE ERROR',
1171 upper(type)||' '||upper(owner)||'.'||upper(name)||
1172 ' has IS/AS keyword on long line - Not rewritten'
1173 from sys.dual;
1174
1175 end if;
1176 -- end if log errors/messages to ad_parallel_compile_errors
1177
1178 return;
1179 end if;
1180 -- end if edited line is too long
1181
1182 ad_apps_private.do_array_assignment(rewrite_a_package.new_owner,
1183 new_source_line, is_as_line+1);
1184
1185 --
1186 -- once we have fetched and processed all source
1187 -- then create the object
1188 --
1189 declare
1190 statement varchar2(256);
1191 name_already_used exception;
1192 pragma exception_init(name_already_used, -955);
1193 begin
1194 statement := 'create or replace ';
1195 -- build the first line of the array of sql statement
1196 ad_apps_private.do_array_assignment(rewrite_a_package.new_owner,
1197 statement, 1);
1198 -- execute the array of statement.
1199 ad_apps_private.do_apps_array_ddl(rewrite_a_package.new_owner,
1200 1, row_count);
1201 exception
1202 when name_already_used then
1203 --
1204 -- This should never happen, but it doesn't hurt to leave this
1205 -- code here
1206 --
1207 -- first reset error buf
1208 ad_apps_private.error_buf := null;
1209 -- drop any synonym by such name and retry
1210 ad_apps_private.drop_object(rewrite_a_package.new_owner,
1211 upper(rewrite_a_package.name), 'SYNONYM');
1212 ad_apps_private.do_apps_array_ddl(rewrite_a_package.new_owner,
1213 1, row_count);
1214 end;
1215
1216 exception
1217 when success_with_comp_error then
1218 --
1219 -- Trap and ignore ORA-24344: success with compilation error
1220 -- This only happens on ORACLE 8
1221 --
1222 -- reset main error buffer
1223 ad_apps_private.error_buf := null;
1224 when others then
1225 declare
1226 sql_error varchar2(1996);
1227 begin
1228 if log_to_table = 'TRUE' then
1229
1230 timestamp := to_char(sysdate,'YYYY-MM-DD:HH24:MI:SS');
1231
1232 insert into ad_parallel_compile_errors (
1233 owner, worker_number, timestamp, type, text)
1234 select upper(owner),
1235 0,
1236 timestamp,
1237 '1 REWRITE ERROR - A',
1238 upper(type)||' '||upper(owner)||'.'||upper(name)||
1239 ': Generic error occurred.'
1240 from sys.dual;
1241
1242 sql_error := SQLERRM;
1243
1244 insert into ad_parallel_compile_errors (
1245 owner, worker_number, timestamp, type, text)
1246 select upper(owner),
1247 0,
1248 timestamp,
1249 '1 REWRITE ERROR - B',
1250 substr(upper(type)||' '||upper(owner)||'.'||upper(name)||
1251 ': '||sql_error,1,1996)
1252 from sys.dual;
1253
1254 if ad_apps_private.error_buf is not null then
1255
1256 insert into ad_parallel_compile_errors (
1257 owner, worker_number, timestamp, type, text)
1258 select upper(owner),
1259 0,
1260 timestamp,
1261 '1 REWRITE ERROR - C',
1262 substr(upper(type)||' '||upper(owner)||'.'||upper(name)||
1263 ': '||ad_apps_private.error_buf,1,1996)
1264 from sys.dual;
1265
1266 end if;
1267 -- error buf contains information
1268
1269 -- clear error buf
1270 ad_apps_private.error_buf := null;
1271
1272 else
1273 raise;
1274 end if;
1275 -- end if log errors/messages to ad_parallel_compile_errors
1276 exception
1277 -- should only fire if we have errors writing to the log table
1278 when others then
1279 ad_apps_private.error_buf := 'rewrite_a_package('
1280 || owner ||', '|| name ||', '|| type ||', '
1281 || new_owner || ', '|| log_to_table ||'): '||
1282 ad_apps_private.error_buf;
1283 raise;
1284 end;
1285 end rewrite_a_package;
1286
1287
1288 procedure rewrite_plsql_array
1289 (the_array in out nocopy dbms_sql.varchar2s,
1290 lb in number,
1291 ub in number,
1292 type in varchar2)
1293 --
1294 -- Rewrites the PL/SQL object creation text stored in the array
1295 -- to use Invoker's Rights.
1296 --
1297 -- DOES NOT CREATE THE OBJECT
1298 --
1299 -- Got most of the logic from rewrite_a_package
1300 --
1301 is
1302 success_with_comp_error exception;
1303 PRAGMA EXCEPTION_INIT(success_with_comp_error, -24344);
1304 source_line varchar2(255);
1305 new_source_line varchar2(300);
1306 found_authid boolean;
1307 authid_line number;
1308 found_is_as boolean;
1309 is_as_line number;
1310 word_location number;
1311 is_as_position number;
1312 we_found_it varchar2(10);
1313 timestamp varchar2(20);
1314 begin
1315 -- Validate PL/SQL object type
1316
1317 if upper(type) <> 'PACKAGE'
1318 and upper(type) <> 'PROCEDURE'
1319 and upper(type) <> 'FUNCTION' then
1320
1321 raise_application_error(-20000,
1322 'Do not know how to rewrite objects of type "'|| upper(type)||'".');
1323
1324 end if;
1325 -- end if not valid type
1326
1327 -- Initialize variables
1328
1329 found_authid := FALSE;
1330 found_is_as := FALSE;
1331
1332 authid_line := 0;
1333 is_as_line := 0;
1334
1335 --
1336 -- loop through and parse source text
1337 --
1338
1339 for counter in lb..ub loop
1340
1341 if not found_is_as then
1342
1343 -- Check for AS
1344
1345 word_location := instr(upper(the_array(counter)),'AS');
1346
1347 if word_location <> 0 then
1348
1349 -- Do more strict checking
1350
1351 verify_token_location(upper(the_array(counter)), 'AS',
1352 we_found_it, word_location);
1353
1354 if we_found_it = 'TRUE' then
1355
1356 found_is_as := TRUE;
1357 is_as_line := counter;
1358 is_as_position := word_location;
1359 source_line := the_array(counter);
1360
1361 end if;
1362 -- end if we really found AS
1363
1364 end if;
1365 -- end if found AS using INSTR
1366
1367 -- Check for IS
1368
1369 word_location := instr(upper(the_array(counter)),'IS');
1370
1371 if word_location <> 0 then
1372
1373 -- Do more strict checking
1374
1375 verify_token_location(upper(the_array(counter)), 'IS',
1376 we_found_it, word_location);
1377
1378 if we_found_it = 'TRUE' then
1379
1380 found_is_as := TRUE;
1381 is_as_line := counter;
1382 is_as_position := word_location;
1383 source_line := the_array(counter);
1384
1385 end if;
1386 -- end if we really found IS
1387
1388 end if;
1389 -- end if found IS using INSTR
1390
1391 -- Check for AUTHID
1392
1393 word_location := instr(upper(the_array(counter)),'AUTHID');
1394
1395 if word_location <> 0 then
1396
1397 -- Do more strict checking
1398
1399 verify_token_location(upper(the_array(counter)), 'AUTHID',
1400 we_found_it, word_location);
1401
1402 if we_found_it = 'TRUE' then
1403
1404 -- We found an AUTHID keyword
1405
1406 found_authid := TRUE;
1407 authid_line := counter;
1408
1409 -- dbms_output.put_line('Found AUTHID at line '||authid_line);
1410
1411 end if;
1412 -- end if we really found AUTHID
1413
1414 end if;
1415 -- end if found AUTHID using INSTR
1416
1417 else
1418 -- if we already found the IS/AS keyword, break out of the loop
1419
1420 exit;
1421
1422 end if;
1423 -- end parse lines until we find the IS/AS keyword
1424
1425 end loop;
1426 -- end loop to get and parse source text
1427
1428 -- just exit if found authid keyword, as nothing needs to be rewritten
1429
1430 if found_authid then
1431 return;
1432 end if;
1433
1434 --
1435 -- Alter the line on which we found the IS|AS
1436 --
1437 -- The parsing above is fairly good, but there are still a
1438 -- few failure cases I can think of (maybe more?):
1439 --
1440 -- 1) it doesn't handle comments
1441 --
1442 -- We will ignore this for now
1443 --
1444 -- 2) if the line is already pretty long, we will fail below if adding
1445 -- AUTHID CURRENT_USER pushes the length past 255
1446 --
1447 -- If the line would be too long, just exit the procedure without
1448 -- rewriting the PL/SQL object. That's probably better than
1449 -- raising an exception. If someone wonders why their PL/SQL
1450 -- object didn't get rewritten, we can always just explain
1451 -- that the rewrite routine doesn't work if the IS/AS keyword
1452 -- is on a long line.
1453 --
1454
1455 if not found_is_as then
1456 --
1457 -- This should never happen
1458 --
1459 -- If it does, exit without rewriting the source text
1460 --
1461
1462 return;
1463
1464 end if;
1465 -- end if didn't find IS/AS keyword
1466
1467 --
1468 -- Rewrite PL/SQL object creation line
1469 --
1470
1471 new_source_line := substr(source_line,1,is_as_position-1)||
1472 'AUTHID CURRENT_USER '||substr(source_line,is_as_position);
1473
1474 if length(new_source_line) > 255 then
1475
1476 raise_application_error(-20000,
1477 'Source text too long at line '||is_as_position);
1478
1479 end if;
1480 -- end if edited line is too long
1481
1482 the_array(is_as_line) := new_source_line;
1483
1484 exception
1485 when others then
1486 ad_apps_private.error_buf := 'rewrite_plsql_array('
1487 || ' <array>, '|| lb ||', ' || ub ||', '
1488 || type || ' ): '||
1489 ad_apps_private.error_buf;
1490 raise;
1491 end rewrite_plsql_array;
1492
1493
1494 procedure grant_pkgs
1495 (worker_num in integer)
1496 --
1497 -- Creates/verifies the correct grants for all packages and Java classes
1498 -- assigned to this worker
1499 --
1500 is
1501 cursor c1 (worker_number in number) is
1502 select rowid, owner, name, type, other_schema,
1503 authid_flag, invoker_flag, done_flag
1504 from ad_invoker_tasks
1505 where phase = 3
1506 and worker = worker_number;
1507 begin
1508 --
1509 -- clear error buffer
1510 --
1511 ad_apps_private.error_buf := null;
1512
1513 for c1_rec in c1(worker_num) loop
1514
1515 if nvl(c1_rec.done_flag,'N') = 'N' then
1516
1517 if (c1_rec.type not like 'JAVA%') then
1518 grant_a_package(c1_rec.owner, c1_rec.name, c1_rec.type,
1519 c1_rec.other_schema, c1_rec.authid_flag, c1_rec.invoker_flag,
1520 'TRUE');
1521 else
1522 grant_a_java_object(c1_rec.owner, c1_rec.name, c1_rec.type,
1523 c1_rec.other_schema, 'TRUE');
1524 end if;
1525
1526 update_done(c1_rec.rowid);
1527
1528 end if;
1529
1530 end loop;
1531
1532 exception
1533 when others then
1534 ad_apps_private.error_buf := 'grant_pkgs('||
1535 worker_num||'): '||
1536 ad_apps_private.error_buf;
1537 raise;
1538 end grant_pkgs;
1539
1540
1541 procedure grant_a_package
1542 (owner in varchar2,
1543 name in varchar2,
1544 type in varchar2,
1545 new_owner in varchar2,
1546 authid_flag in varchar2,
1547 invoker_flag in varchar2,
1548 log_to_table in varchar2)
1549 --
1550 -- Creates/verifies the correct grants for a specific package
1551 --
1552 -- if log_to_table is 'TRUE', writes errors to ad_parallel_compile_errors
1553 --
1554 is
1555 invoker_plsql boolean;
1556 definer_plsql boolean;
1557 nosync_plsql boolean;
1558 statement varchar2(200);
1559 synonym_ok boolean;
1560 any_obj_w_name boolean;
1561 type_of_object varchar2(30);
1562 obj_type_new varchar2(30);
1563 timestamp varchar2(20);
1564 exact_code_match varchar2(10);
1565 begin
1566 -- dbms_output.put_line('grant_a_package('
1567 -- || owner ||', '|| name ||', '|| type ||', '|| new_owner
1568 -- || ', '|| authid_flag || ', '|| invoker_flag
1569 -- || ', '|| log_to_table ||')');
1570 -- return;
1571
1572 -- Validate PL/SQL object type
1573
1574 if upper(type) <> 'PACKAGE'
1575 and upper(type) <> 'PROCEDURE'
1576 and upper(type) <> 'FUNCTION' then
1577
1578 if log_to_table = 'TRUE' then
1579
1580 timestamp := to_char(sysdate,'YYYY-MM-DD:HH24:MI:SS');
1581
1582 insert into ad_parallel_compile_errors (
1583 owner, worker_number, timestamp, type, text)
1584 select upper(owner),
1585 0,
1586 timestamp,
1587 '3 GRANT ERROR',
1588 upper(type)||' '||upper(owner)||'.'||upper(name)||
1589 ': Object type "'||upper(type)||'" not supported.'
1590 from sys.dual;
1591
1592 return;
1593
1594 else
1595
1596 raise_application_error(-20000,upper(type)||' '||upper(owner)||
1597 '.'||upper(name)||': Object type "'||upper(type)||
1598 '" not supported.');
1599
1600 end if;
1601 -- end if log errors/messages to ad_parallel_compile_errors
1602
1603 end if;
1604 -- end if not valid type
1605
1606 -- Init variables
1607
1608 invoker_plsql := FALSE;
1609 definer_plsql := FALSE;
1610 nosync_plsql := FALSE;
1611
1612 --
1613 -- Decide how to handle this PL/SQL object, based on
1614 -- authid_flag and invoker_flag
1615
1616 if authid_flag = 'N' then
1617
1618 definer_plsql := TRUE;
1619
1620 elsif authid_flag = 'Y' then
1621
1622 if invoker_flag = 'I' then
1623
1624 invoker_plsql := TRUE;
1625
1626 elsif invoker_flag = 'D' then
1627
1628 definer_plsql := TRUE;
1629
1630 elsif invoker_flag = 'S' then
1631
1632 nosync_plsql := TRUE;
1633
1634 else
1635
1636 if log_to_table = 'TRUE' then
1637
1638 timestamp := to_char(sysdate,'YYYY-MM-DD:HH24:MI:SS');
1639
1640 insert into ad_parallel_compile_errors (
1641 owner, worker_number, timestamp, type, text)
1642 select upper(owner),
1643 0,
1644 timestamp,
1645 '3 GRANT ERROR',
1646 upper(type)||' '||upper(owner)||'.'||upper(name)||
1647 ': Invalid value for invoker_flag: "'||invoker_flag||'"'
1648 from sys.dual;
1649
1650 return;
1651
1652 else
1653
1654 raise_application_error(-20000,upper(type)||' '||upper(owner)||
1655 '.'||upper(name)||': Invalid value for invoker_flag: "'||
1656 invoker_flag||'"');
1657
1658 end if;
1659 -- end if log errors to table
1660
1661 end if;
1662 -- end if statement to handle/validate settings for invoker_flag
1663
1664 else
1665
1666 if log_to_table = 'TRUE' then
1667
1668 timestamp := to_char(sysdate,'YYYY-MM-DD:HH24:MI:SS');
1669
1670 insert into ad_parallel_compile_errors (
1671 owner, worker_number, timestamp, type, text)
1672 select upper(owner),
1673 0,
1674 timestamp,
1675 '3 GRANT ERROR',
1676 upper(type)||' '||upper(owner)||'.'||upper(name)||
1677 ': Invalid value for authid_flag: "'||authid_flag||'"'
1678 from sys.dual;
1679
1680 return;
1681
1682 else
1683
1684 raise_application_error(-20000,upper(type)||' '||upper(owner)||
1685 '.'||upper(name)||': Invalid value for authid_flag: "'||
1686 authid_flag||'"');
1687
1688 end if;
1689 -- end if log errors to table
1690
1691 end if;
1692 -- end if statement to figure out how to handle this PL/SQL object
1693
1694 --
1695 -- Perform correct logic based on classification of this PL/SQL object
1696 --
1697
1698 if invoker_plsql then
1699
1700 --
1701 -- Create grant
1702 --
1703
1704 statement := 'grant all on "'||upper(name)||'" to '||upper(new_owner)||
1705 ' with grant option';
1706
1707 ad_apps_private.do_apps_ddl(upper(owner), statement);
1708
1709 --
1710 -- Check for correct synonym
1711 --
1712
1713 ad_apps_private.exact_synonym_match(upper(new_owner), upper(name),
1714 upper(owner), upper(name), synonym_ok, any_obj_w_name,
1715 type_of_object);
1716
1717 if not synonym_ok then
1718
1719 --
1720 -- drop any existing object with this name
1721 --
1722
1723 if any_obj_w_name then
1724
1725 if type_of_object = 'PKG_S_AND_B'
1726 or type_of_object = 'PACKAGE'
1727 or type_of_object = 'PACKAGE BODY' then
1728 -- existing object is package
1729
1730 ad_apps_private.drop_object(upper(new_owner), upper(name),
1731 'PACKAGE');
1732 else
1733 -- existing object not package
1734
1735 ad_apps_private.drop_object(upper(new_owner), upper(name),
1736 type_of_object);
1737 end if;
1738 -- end if existing object is package
1739
1740 end if;
1741 -- end if any existing object with this name
1742
1743 --
1744 -- then create correct synonym
1745 --
1746
1747 statement := 'create synonym '||upper(name)||' for '||upper(owner)||
1748 '.'||upper(name);
1749
1750 ad_apps_private.do_apps_ddl(upper(new_owner), statement);
1751
1752 end if;
1753 -- end if synonym was not exactly correct
1754
1755 elsif definer_plsql then
1756
1757 --
1758 -- Check to see if there is any object in the other schema
1759 -- with this name
1760 --
1761
1762 ad_apps_private.exact_synonym_match(upper(new_owner), upper(name),
1763 upper(owner), upper(name), synonym_ok, any_obj_w_name,
1764 type_of_object);
1765
1766 if any_obj_w_name then
1767
1768 --
1769 -- if not the right type of object, drop it and recreate as
1770 -- a copy of the current object
1771 --
1772
1773 if type_of_object <> upper(type)
1774 and not ( upper(type) = 'PACKAGE'
1775 and type_of_object = 'PKG_S_AND_B') then
1776
1777 --
1778 -- Drop existing object from other schema
1779 --
1780
1781 if type_of_object = 'PKG_S_AND_B'
1782 or type_of_object = 'PACKAGE'
1783 or type_of_object = 'PACKAGE BODY' then
1784 -- existing object is package
1785
1786 ad_apps_private.drop_object(upper(new_owner), upper(name),
1787 'PACKAGE');
1788 else
1789 -- existing object not package
1790
1791 ad_apps_private.drop_object(upper(new_owner), upper(name),
1792 type_of_object);
1793 end if;
1794 -- end if existing object is package
1795
1796 --
1797 -- Create a copy of this object in the other schema
1798 --
1799
1800 ad_apps_private.copy_code(upper(name), upper(type), upper(owner),
1801 upper(new_owner));
1802
1803 --
1804 -- If object is a package and the package body exists
1805 -- in the source schema, also copy the package body
1806 -- to the other schema
1807 --
1808
1809 ad_apps_private.exact_synonym_match(upper(owner), upper(name),
1810 upper(owner), upper(name), synonym_ok, any_obj_w_name,
1811 type_of_object);
1812
1813 if any_obj_w_name and type_of_object = 'PKG_S_AND_B' then
1814
1815 ad_apps_private.copy_code(upper(name), 'PACKAGE BODY', upper(owner),
1816 upper(new_owner));
1817
1818 end if;
1819 -- end if object is package spec, and corresponding body exists
1820
1821 else
1822
1823 --
1824 -- Correct type in other schema
1825 -- Compare to validate that it exactly matches the object
1826 -- from the owner schema
1827 --
1828
1829 ad_apps_private.compare_code(upper(name), upper(type), upper(owner),
1830 upper(new_owner), 'FULL', exact_code_match);
1831
1832 --
1833 -- If code matches exactly, don't do anything
1834 -- If code doesn't match exactly, recopy code from owner schema
1835 -- to new schema
1836 --
1837
1838 if exact_code_match <> 'TRUE' then
1839
1840 ad_apps_private.copy_code(upper(name), upper(type), upper(owner),
1841 upper(new_owner));
1842
1843 end if;
1844 -- end if code does not match exactly
1845
1846 --
1847 -- If object is a package and the package body exists
1848 -- in the source schema, also compare the package body text
1849 -- with the package body in the other schema
1850 --
1851
1852 -- save object type in other schema for use below
1853
1854 obj_type_new := type_of_object;
1855
1856 -- now find out if this is a package that also has a body
1857
1858 ad_apps_private.exact_synonym_match(upper(owner), upper(name),
1859 upper(owner), upper(name), synonym_ok, any_obj_w_name,
1860 type_of_object);
1861
1862 if any_obj_w_name and type_of_object = 'PKG_S_AND_B' then
1863
1864 --
1865 -- if type in other schema is just 'PACKAGE', unconditionally
1866 -- copy the body over
1867 --
1868 -- if type is 'PKG_S_AND_B', then compare the bodies and then
1869 -- only copy the body over if not identical
1870 --
1871
1872 if obj_type_new = 'PACKAGE' then
1873
1874 ad_apps_private.copy_code(upper(name), 'PACKAGE BODY',
1875 upper(owner), upper(new_owner));
1876
1877 elsif obj_type_new = 'PKG_S_AND_B' then
1878
1879 --
1880 -- Compare pkg bodies
1881 --
1882
1883 ad_apps_private.compare_code(upper(name), 'PACKAGE BODY',
1884 upper(owner), upper(new_owner), 'FULL', exact_code_match);
1885
1886 --
1887 -- If code matches exactly, don't do anything
1888 -- If code doesn't match exactly, recopy code from owner schema
1889 -- to new schema
1890 --
1891
1892 if exact_code_match <> 'TRUE' then
1893
1894 ad_apps_private.copy_code(upper(name), 'PACKAGE BODY',
1895 upper(owner), upper(new_owner));
1896
1897 end if;
1898 -- end if code does not match exactly
1899
1900 else
1901
1902 if log_to_table = 'TRUE' then
1903
1904 timestamp := to_char(sysdate,'YYYY-MM-DD:HH24:MI:SS');
1905
1906 insert into ad_parallel_compile_errors (
1907 owner, worker_number, timestamp, type, text)
1908 select upper(owner),
1909 0,
1910 timestamp,
1911 '3 GRANT ERROR',
1912 upper(type)||' '||upper(owner)||'.'||upper(name)||
1913 ': Internal error [pkg]'
1914 from sys.dual;
1915
1916 return;
1917
1918 else
1919
1920 raise_application_error(-20000,upper(type)||' '||upper(owner)||
1921 '.'||upper(name)||': Internal error [pkg]');
1922
1923 end if;
1924 -- end if log errors to table
1925
1926 end if;
1927 -- end if this is a package spec and body combination, but
1928 -- only the spec exists in the other schema
1929
1930 end if;
1931 -- end if object is package spec, and corresponding body exists
1932
1933 end if;
1934 -- end if object types differ
1935
1936 else
1937
1938 --
1939 -- No object with this name. Copy object to other schema
1940 --
1941
1942 ad_apps_private.copy_code(upper(name), upper(type), upper(owner),
1943 upper(new_owner));
1944
1945 --
1946 -- If object is a package and the package body exists
1947 -- in the source schema, also copy the package body
1948 -- to the other schema
1949 --
1950
1951 ad_apps_private.exact_synonym_match(upper(owner), upper(name),
1952 upper(owner), upper(name), synonym_ok, any_obj_w_name,
1953 type_of_object);
1954
1955 if any_obj_w_name and type_of_object = 'PKG_S_AND_B' then
1956
1957 ad_apps_private.copy_code(upper(name), 'PACKAGE BODY', upper(owner),
1958 upper(new_owner));
1959
1960 end if;
1961 -- end if object is package spec, and corresponding body exists
1962
1963 end if;
1964 -- end if there is already an object in the dest schema with this name
1965
1966 elsif nosync_plsql then
1967
1968 -- Don't do anything for Definer's Rights PL/SQL that contains the
1969 -- /*nosync*/ comment
1970
1971 return;
1972
1973 else
1974
1975 if log_to_table = 'TRUE' then
1976
1977 timestamp := to_char(sysdate,'YYYY-MM-DD:HH24:MI:SS');
1978
1979 insert into ad_parallel_compile_errors (
1980 owner, worker_number, timestamp, type, text)
1981 select upper(owner),
1982 0,
1983 timestamp,
1984 '3 GRANT ERROR',
1985 upper(type)||' '||upper(owner)||'.'||upper(name)||
1986 ': Internal error [classification]'
1987 from sys.dual;
1988
1989 return;
1990
1991 else
1992
1993 raise_application_error(-20000,upper(type)||' '||upper(owner)||
1994 '.'||upper(name)||': Internal error [classification]');
1995
1996 end if;
1997 -- end if log errors to table
1998
1999 end if;
2000 -- End process PL/SQL object based on its type
2001
2002 exception
2003 when others then
2004 declare
2005 sql_error varchar2(1996);
2006 begin
2007 if log_to_table = 'TRUE' then
2008
2009 timestamp := to_char(sysdate,'YYYY-MM-DD:HH24:MI:SS');
2010
2011 insert into ad_parallel_compile_errors (
2012 owner, worker_number, timestamp, type, text)
2013 select upper(owner),
2014 0,
2015 timestamp,
2016 '3 GRANT ERROR - A',
2017 upper(type)||' '||upper(owner)||'.'||upper(name)||
2018 ': Generic error occurred.'
2019 from sys.dual;
2020
2021 sql_error := SQLERRM;
2022
2023 insert into ad_parallel_compile_errors (
2024 owner, worker_number, timestamp, type, text)
2025 select upper(owner),
2026 0,
2027 timestamp,
2028 '3 GRANT ERROR - B',
2029 substr(upper(type)||' '||upper(owner)||'.'||upper(name)||
2030 ': '||sql_error,1,1996)
2031 from sys.dual;
2032
2033 if ad_apps_private.error_buf is not null then
2034
2035 insert into ad_parallel_compile_errors (
2036 owner, worker_number, timestamp, type, text)
2037 select upper(owner),
2038 0,
2039 timestamp,
2040 '3 GRANT ERROR - C',
2041 substr(upper(type)||' '||upper(owner)||'.'||upper(name)||
2042 ': '||ad_apps_private.error_buf,1,1996)
2043 from sys.dual;
2044
2045 end if;
2046 -- error buf contains information
2047
2048 -- clear error buf
2049 ad_apps_private.error_buf := null;
2050
2051 else
2052 raise;
2053 end if;
2054 -- end if log errors/messages to ad_parallel_compile_errors
2055 exception
2056 -- should only fire if we have errors writing to the log table
2057 when others then
2058 ad_apps_private.error_buf := 'grant_a_package('
2059 || owner ||', '|| name ||', '|| type ||', '|| new_owner
2060 || ', '|| authid_flag || ', '|| invoker_flag
2061 || ', '|| log_to_table ||'): '||
2062 ad_apps_private.error_buf;
2063 raise;
2064 end;
2065 end grant_a_package;
2066
2067 procedure grant_a_java_object
2068 (owner in varchar2,
2069 name in varchar2,
2070 type in varchar2,
2071 new_owner in varchar2,
2072 log_to_table in varchar2)
2073 --
2074 -- Creates/verifies the correct grants for a specific Java object
2075 --
2076 -- if log_to_table is 'TRUE', writes errors to ad_parallel_compile_errors
2077 --
2078 is
2079 statement varchar2(200);
2080 synonym_ok boolean;
2081 any_obj_w_name boolean;
2082 type_of_object varchar2(30);
2083 obj_type_new varchar2(30);
2084 timestamp varchar2(20);
2085 begin
2086 -- Validate Java object type
2087
2088 if (upper(type) not in ('JAVA CLASS')) then
2089
2090 if log_to_table = 'TRUE' then
2091
2092 timestamp := to_char(sysdate,'YYYY-MM-DD:HH24:MI:SS');
2093
2094 insert into ad_parallel_compile_errors (
2095 owner, worker_number, timestamp, type, text)
2096 select upper(owner),
2097 0,
2098 timestamp,
2099 '3 GRANT ERROR',
2100 upper(type)||' '||upper(owner)||'.'||name||
2101 ': Object type "'||upper(type)||'" not supported.'
2102 from sys.dual;
2103
2104 return;
2105
2106 else
2107
2108 raise_application_error(-20000,upper(type)||' '||upper(owner)||
2109 '.'||name||': Object type "'||upper(type)||
2110 '" not supported.');
2111
2112 end if;
2113 -- end if log errors/messages to ad_parallel_compile_errors
2114
2115 end if;
2116 -- end if not valid type
2117
2118 --
2119 -- Create grant
2120 --
2121
2122 statement := 'grant all on "'||name||'" to '||upper(new_owner)||
2123 ' with grant option';
2124
2125 ad_apps_private.do_apps_ddl(upper(owner), statement);
2126
2127 --
2128 -- Check for correct synonym
2129 --
2130
2131 ad_apps_private.exact_synonym_match(upper(new_owner), name,
2132 upper(owner), name, synonym_ok, any_obj_w_name,
2133 type_of_object);
2134
2135 if not synonym_ok then
2136
2137 --
2138 -- drop any existing object with this name
2139 --
2140
2141 if any_obj_w_name then
2142
2143 if type_of_object = 'JAVA CLASS'
2144 or type_of_object = 'JAVA RESOURCE' then
2145 -- existing object is Java object
2146
2147 ad_apps_private.drop_object(upper(new_owner), name,
2148 type_of_object);
2149 else
2150 -- existing object not Java object
2151
2152
2153 ad_apps_private.drop_object(upper(new_owner), name,
2154 type_of_object);
2155 end if;
2156 -- end if existing object is Java object
2157
2158 end if;
2159 -- end if any existing object with this name
2160
2161 --
2162 -- then create correct synonym
2163 --
2164
2165 statement := 'create synonym "'||name||'" for '||upper(owner)||
2166 '."'||name||'"';
2167
2168 ad_apps_private.do_apps_ddl(upper(new_owner), statement);
2169
2170 end if;
2171 -- end if synonym was not exactly correct
2172
2173 -- End process Java object
2174
2175 exception
2176 when others then
2177 declare
2178 sql_error varchar2(1996);
2179 begin
2180 if log_to_table = 'TRUE' then
2181
2182 timestamp := to_char(sysdate,'YYYY-MM-DD:HH24:MI:SS');
2183
2184 insert into ad_parallel_compile_errors (
2185 owner, worker_number, timestamp, type, text)
2186 select upper(owner),
2187 0,
2188 timestamp,
2189 '3 GRANT ERROR - A',
2190 upper(type)||' '||upper(owner)||'.'||name||
2191 ': Generic error occurred.'
2192 from sys.dual;
2193
2194 sql_error := SQLERRM;
2195
2196 insert into ad_parallel_compile_errors (
2197 owner, worker_number, timestamp, type, text)
2198 select upper(owner),
2199 0,
2200 timestamp,
2201 '3 GRANT ERROR - B',
2202 substr(upper(type)||' '||upper(owner)||'.'||name||
2203 ': '||sql_error,1,1996)
2204 from sys.dual;
2205
2206 if ad_apps_private.error_buf is not null then
2207
2208 insert into ad_parallel_compile_errors (
2209 owner, worker_number, timestamp, type, text)
2210 select upper(owner),
2211 0,
2212 timestamp,
2213 '3 GRANT ERROR - C',
2214 substr(upper(type)||' '||upper(owner)||'.'||name||
2215 ': '||ad_apps_private.error_buf,1,1996)
2216 from sys.dual;
2217
2218 end if;
2219 -- error buf contains information
2220
2221 -- clear error buf
2222 ad_apps_private.error_buf := null;
2223
2224 else
2225 raise;
2226 end if;
2227 -- end if log errors/messages to ad_parallel_compile_errors
2228 exception
2229 -- should only fire if we have errors writing to the log table
2230 when others then
2231 ad_apps_private.error_buf := 'grant_a_java_object('
2232 || owner ||', '|| name ||', '|| type ||', '|| new_owner
2233 || ', '|| log_to_table ||'): '||
2234 ad_apps_private.error_buf;
2235 raise;
2236 end;
2237 end grant_a_java_object;
2238
2239
2240
2241 -- Bug 3611969 : FIXED FILE.SQL.35 GSCC WARNINGS
2242 -- sraghuve (07/05/2004)
2243
2244 procedure update_timestamp
2245 (in_type in varchar2,
2246 in_attribute in varchar2)
2247 is
2248 begin
2249 update_timestamp
2250 (in_type => in_type,
2251 in_attribute => in_attribute,
2252 in_timestamp => sysdate);
2253
2254 end;
2255
2256
2257
2258 procedure update_timestamp
2259 (in_type in varchar2,
2260 in_attribute in varchar2,
2261 in_timestamp in date)
2262 --
2263 -- Updates/Inserts the row in AD_TIMESTAMPS for the specified
2264 -- type and attribute
2265 --
2266 is
2267 begin
2268 --
2269 -- First try to update
2270 --
2271 update ad_timestamps
2272 set timestamp = in_timestamp
2273 where type = in_type
2274 and attribute = in_attribute;
2275
2276 if SQL%ROWCOUNT = 1 then
2277 return;
2278 end if;
2279 --
2280 -- Insert if no rows updated
2281 --
2282 insert into ad_timestamps
2283 (type, attribute, timestamp)
2284 values (in_type, in_attribute, in_timestamp);
2285
2286 exception
2287 when others then
2288 ad_apps_private.error_buf := 'update_timestamp('
2289 || in_type ||', '|| in_attribute ||', '||
2290 to_char(in_timestamp,'YYYY-MM-DD:HH24:MI:SS') ||'): '||
2291 ad_apps_private.error_buf;
2292 raise;
2293 end update_timestamp;
2294
2295
2296 procedure verify_token_location
2297 (input_string in varchar2,
2298 input_token in varchar2,
2299 token_found out nocopy varchar2,
2300 token_location out nocopy number)
2301 --
2302 -- Makes sure a given token does exist as a word in the input string
2303 -- A word is delimited by white space on either side
2304 -- (unless at the beginning or end of the string, in which case it is
2305 -- only delimited by white space on one side)
2306 --
2307 -- token_found returns either 'TRUE' or 'FALSE'
2308 --
2309 -- token_location is the index of the token in the string (if found)
2310 -- It's the same value that would be returned by the INSTR function
2311 --
2312 -- If the given token exists in multiple places in the string as a word,
2313 -- we just return the first occurrence
2314 --
2315 -- Added (SYS_CONTEXT('USERENV','LANGUAGE') for MRC bug 3697501
2316 --
2317
2318
2319 is
2320
2321 a_space constant varchar2(10) :=
2322 CONVERT(CHR(32), substr(SYS_CONTEXT('USERENV','LANGUAGE'),
2323 instr(SYS_CONTEXT('USERENV','LANGUAGE'),'.')+1),
2324 'US7ASCII');
2325
2326 a_tab constant varchar2(10) :=
2327 CONVERT(CHR(9), substr(SYS_CONTEXT('USERENV','LANGUAGE'),
2328 instr(SYS_CONTEXT('USERENV','LANGUAGE'),'.')+1),
2329 'US7ASCII');
2330
2331 a_newline constant varchar2(10) :=
2332 CONVERT(CHR(10), substr(SYS_CONTEXT('USERENV','LANGUAGE'),
2333 instr(SYS_CONTEXT('USERENV','LANGUAGE'),'.')+1),
2334 'US7ASCII');
2335
2336 a_carr_return constant varchar2(10) :=
2337 CONVERT(CHR(13), substr(SYS_CONTEXT('USERENV','LANGUAGE'),
2338 instr(SYS_CONTEXT('USERENV','LANGUAGE'),'.')+1),
2339 'US7ASCII');
2340
2341 token_index number;
2342 look_for_next number;
2343 string_length number;
2344 token_length number;
2345 begin
2346 string_length := length(input_string);
2347 token_length := length(input_token);
2348 look_for_next := 1;
2349
2350 --
2351 -- Find first occurrence of token in string that is
2352 -- delimited by white space.
2353 -- If find an occurrence that is not delimited by white space
2354 -- look for the next occurrence
2355 -- Break out of loop if found token delimited by white space
2356 -- or if couldn't find the token delmited by white space
2357 --
2358 loop
2359 token_index := instr(input_string,input_token,1,look_for_next);
2360
2361 -- Exit if we didn't find the token
2362
2363 if token_index = 0 then
2364 exit;
2365 end if;
2366
2367 -- Check for white space before token
2368
2369 if token_index > 1 then
2370
2371 if substr(input_string,token_index-1,1) <> a_space
2372 and substr(input_string,token_index-1,1) <> a_tab
2373 and substr(input_string,token_index-1,1) <> a_newline
2374 and substr(input_string,token_index-1,1) <> a_carr_return then
2375
2376 goto try_next_occurrence;
2377
2378 end if;
2379 -- end if no white space before token
2380
2381 end if;
2382 -- end if token not at start of string
2383
2384 -- Check for white space after token
2385
2386 if token_index+token_length <= string_length then
2387
2388 if substr(input_string,token_index+token_length,1) <> a_space
2389 and substr(input_string,token_index+token_length,1) <> a_tab
2390 and substr(input_string,token_index+token_length,1) <> a_newline
2391 and substr(input_string,token_index+token_length,1) <> a_carr_return
2392 then
2393
2394 goto try_next_occurrence;
2395
2396 else
2397
2398 -- Found token delimited by white space
2399
2400 exit;
2401
2402 end if;
2403 -- end if no white space after token
2404
2405 else
2406
2407 -- Found token at end of string
2408 exit;
2409
2410 end if;
2411 -- end if token not at end of string
2412
2413 <<try_next_occurrence>>
2414
2415 look_for_next := look_for_next + 1;
2416
2417 end loop;
2418
2419 -- Set return values
2420
2421 token_location := token_index;
2422
2423 if token_index = 0 then
2424 token_found := 'FALSE';
2425 else
2426 token_found := 'TRUE';
2427 end if;
2428
2429 exception
2430 when others then
2431 ad_apps_private.error_buf := 'verify_token_location('
2432 || input_string ||', '|| input_token ||'): '||
2433 ad_apps_private.error_buf;
2434 raise;
2435 end verify_token_location;
2436
2437
2438 procedure classify_plsql_object
2439 (owner in varchar2,
2440 name in varchar2,
2441 type in varchar2,
2442 has_authid out nocopy varchar2,
2443 invoker_flag out nocopy varchar2)
2444 --
2445 -- Parses the source text for the given PL/SQL object
2446 --
2447 -- Sets has_authid to 'TRUE' if the object contains the AUTHID keyword
2448 -- sets has_authid to 'FALSE' otherwise
2449 --
2450 -- Sets invoker_flag to 'I' (Invoker's Rights; AUTHID CURRENT_USER)
2451 -- or 'D' (Definer's Rights; AUTHID DEFINER) if has_authid is 'TRUE'
2452 -- Sets invoker_flag to 'S' for Definer's Rights packages containing
2453 -- the /*nosync*/ comment (exactly as written, and delimited by whitespace)
2454 -- The /*nosync*/ comment must appear before the IS/AS keyword.
2455 --
2456 -- For wrapped package specs (procedures, functions), assumes definer's
2457 -- rights, as we really have no way to parse them. Not clear why anyone
2458 -- would want to wrap these objects, though...
2459 --
2460 -- 2/6/01 R Lotero
2461 --
2462 -- Add "customer hack" for Fidelity. If package doesn't contain an AUTHID
2463 -- clause, and package doesn't contain a valid Header string either, assume
2464 -- it's not an Oracle Apps package and maintain the default behavior (no
2465 -- AUTHID clause implies Definer Rights). To do this, say we found an AUTHID
2466 -- clause and that the package was explicitly declared as Definer Rights,
2467 -- even though this is not true.
2468 --
2469 is
2470 cursor c1 is
2471 select text from dba_source
2472 where owner = upper(classify_plsql_object.owner)
2473 and name = upper(classify_plsql_object.name)
2474 and type = upper(classify_plsql_object.type)
2475 order by line;
2476 cursor PKG_HEADER (c_owner in varchar2,
2477 c_name in varchar2,
2478 c_type in varchar2) is
2479 select
2480 substr(s.text, instr(s.text,'$Header'||': '),
2481 ((instr(s.text,' $', instr(s.text,'$Header'||': ')) + 2)
2482 - instr(s.text,'$Header'||': ')))
2483 from dba_source s
2484 where s.owner= upper(c_owner)
2485 and s.name = upper(c_name)
2486 and s.type = upper(c_type)
2487 and s.line between 2 and 5
2488 and s.text like '%$Header'||': % $%';
2489 header_string varchar2(500);
2490 row_count number;
2491 found_authid boolean;
2492 authid_line number;
2493 found_is_as boolean;
2494 found_wrapped boolean;
2495 is_as_line number;
2496 word_location number;
2497 is_as_position number;
2498 we_found_it varchar2(10);
2499 found_aid_type boolean;
2500 aid_type_line number;
2501 authid_type varchar2(10);
2502 found_nosync boolean;
2503 nosync_line number;
2504 begin
2505 -- Initialize return variables
2506
2507 has_authid := 'FALSE';
2508 invoker_flag := 'X';
2509
2510 -- Validate PL/SQL object type
2511
2512 if upper(type) <> 'PACKAGE'
2513 and upper(type) <> 'PROCEDURE'
2514 and upper(type) <> 'FUNCTION' then
2515
2516 raise_application_error(-20000,
2517 'Do not know how to classify objects of type "'||upper(type)||'".');
2518
2519 end if;
2520 -- end if not valid type
2521
2522 -- Initialize variables
2523
2524 found_authid := FALSE;
2525 found_is_as := FALSE;
2526 found_aid_type := FALSE;
2527 found_nosync := FALSE;
2528 found_wrapped := FALSE;
2529
2530 authid_line := 0;
2531 is_as_line := 0;
2532 aid_type_line := 0;
2533 nosync_line := 0;
2534
2535 --
2536 -- parse the source text
2537 --
2538 -- Exit loop when we find the IS/AS keyword
2539 --
2540
2541 row_count := 0;
2542
2543 for c1rec in c1 loop
2544
2545 row_count:=row_count+1;
2546
2547 -- Check for AUTHID
2548
2549 word_location := instr(upper(c1rec.text),'AUTHID');
2550
2551 if word_location <> 0 then
2552
2553 -- Do more strict checking
2554
2555 verify_token_location(upper(c1rec.text), 'AUTHID',
2556 we_found_it, word_location);
2557
2558 if we_found_it = 'TRUE' then
2559
2560 found_authid := TRUE;
2561 authid_line := row_count;
2562
2563 end if;
2564 -- end if we really found AUTHID
2565
2566 end if;
2567 -- end if found AUTHID using INSTR
2568
2569 -- If found AUTHID, check for authid type
2570
2571 if found_authid then
2572
2573 -- Check for CURRENT_USER keyword
2574
2575 word_location := instr(upper(c1rec.text),'CURRENT_USER');
2576
2577 if word_location <> 0 then
2578
2579 -- Do more strict checking
2580
2581 verify_token_location(upper(c1rec.text), 'CURRENT_USER',
2582 we_found_it, word_location);
2583
2584 if we_found_it = 'TRUE' then
2585
2586 found_aid_type := TRUE;
2587 aid_type_line := row_count;
2588 authid_type := 'I';
2589
2590 end if;
2591 -- end if we really found CURRENT_USER
2592
2593 end if;
2594 -- end if found CURRENT_USER using INSTR
2595
2596 -- Check for DEFINER keyword
2597
2598 word_location := instr(upper(c1rec.text),'DEFINER');
2599
2600 if word_location <> 0 then
2601
2602 -- Do more strict checking
2603
2604 verify_token_location(upper(c1rec.text), 'DEFINER',
2605 we_found_it, word_location);
2606
2607 if we_found_it = 'TRUE' then
2608
2609 found_aid_type := TRUE;
2610 aid_type_line := row_count;
2611 authid_type := 'D';
2612
2613 end if;
2614 -- end if we really found DEFINER
2615
2616 end if;
2617 -- end if found DEFINER using INSTR
2618
2619 end if;
2620 -- end if check for AUTHID type
2621
2622 -- Check for /*nosync*/ comment
2623 -- Must be specified exactly as above (case-insensitive) and be
2624 -- delimited by whitespace
2625
2626 word_location := instr(upper(c1rec.text),'/*NOSYNC*/');
2627
2628 if word_location <> 0 then
2629
2630 -- Do more strict checking
2631
2632 verify_token_location(upper(c1rec.text), '/*NOSYNC*/',
2633 we_found_it, word_location);
2634
2635 if we_found_it = 'TRUE' then
2636
2637 found_nosync := TRUE;
2638 nosync_line := row_count;
2639
2640 end if;
2641 -- end if we really found /*NOSYNC*/
2642
2643 end if;
2644 -- end if found /*NOSYNC*/ using INSTR
2645
2646 -- Check for AS
2647 -- Break out of the loop if we find it
2648
2649 word_location := instr(upper(c1rec.text),'AS');
2650
2651 if word_location <> 0 then
2652
2653 -- Do more strict checking
2654
2655 verify_token_location(upper(c1rec.text), 'AS',
2656 we_found_it, word_location);
2657
2658 if we_found_it = 'TRUE' then
2659
2660 found_is_as := TRUE;
2661 is_as_line := row_count;
2662 exit;
2663
2664 end if;
2665 -- end if we really found AS
2666
2667 end if;
2668 -- end if found AS using INSTR
2669
2670 -- Check for IS
2671 -- Break out of the loop if we find it
2672
2673 word_location := instr(upper(c1rec.text),'IS');
2674
2675 if word_location <> 0 then
2676
2677 -- Do more strict checking
2678
2679 verify_token_location(upper(c1rec.text), 'IS',
2680 we_found_it, word_location);
2681
2682 if we_found_it = 'TRUE' then
2683
2684 found_is_as := TRUE;
2685 is_as_line := row_count;
2686 exit;
2687
2688 end if;
2689 -- end if we really found IS
2690
2691 end if;
2692 -- end if found IS using INSTR
2693
2694 -- Check for WRAPPED
2695 -- Just make a note of it if we find it
2696
2697 word_location := instr(upper(c1rec.text),'WRAPPED');
2698
2699 if word_location <> 0 then
2700
2701 -- Do more strict checking
2702
2703 verify_token_location(upper(c1rec.text), 'WRAPPED',
2704 we_found_it, word_location);
2705
2706 if we_found_it = 'TRUE' then
2707
2708
2709 found_wrapped := TRUE;
2710 is_as_line := row_count;
2711 exit;
2712
2713 end if;
2714 -- end if we really found WRAPPED
2715
2716 end if;
2717 -- end if found WRAPPED using INSTR
2718
2719 end loop;
2720 -- end loop to parse source text
2721
2722 if not found_is_as then
2723
2724 -- Should only happen for wrapped package specs,
2725 -- wrapped procedures, or wrapped functions
2726
2727 if found_wrapped then
2728
2729 -- It's wierd to wrap a package spec, procedure, or function
2730 -- It's also annoying, because then we can't parse it to find
2731 -- out if it's invoker's rights or definer's rights.
2732 --
2733 -- Treat all wrapped specs, procedures, or functions as
2734 -- definer's rights objects. This is the safest strategy.
2735 --
2736
2737 has_authid := 'TRUE';
2738 invoker_flag := 'D';
2739 return;
2740
2741 else
2742
2743 --
2744 -- This should never happen, but it happens on Dev115
2745 -- Use the "safe" strategy from above: say it's Definer's Rights
2746 --
2747
2748 has_authid := 'TRUE';
2749 invoker_flag := 'D';
2750 return;
2751
2752 -- raise_application_error(-20000,
2753 -- 'No IS/AS keyword found in '||upper(type)||' '||
2754 -- upper(owner)||'.'||upper(name));
2755
2756 end if;
2757 -- end if found WRAPPED keyword
2758
2759 end if;
2760 -- end if didn't find IS/AS keyword
2761
2762 -- Set return values
2763
2764 if found_authid then
2765
2766 has_authid := 'TRUE';
2767
2768 if found_aid_type then
2769
2770 if authid_type = 'D' or authid_type = 'I' then
2771
2772 --
2773 -- Reset authid_type to 'S' for Definer's Rights objects
2774 -- that contain the /*nosync*/ comment
2775 --
2776 if authid_type = 'D' then
2777 if found_nosync then
2778 authid_type := 'S';
2779 end if;
2780 end if;
2781
2782 invoker_flag := authid_type;
2783 else
2784 raise_application_error(-20000,
2785 'Found AUTHID keyword, but did not find authid type');
2786 end if;
2787 -- end if valid authid type
2788
2789 end if;
2790 -- end if found authid type
2791
2792 else
2793
2794 -- Didn't find AUTHID keyword.
2795
2796 -- Check for valid Header string in package. If found, don't do anything.
2797 -- If not found, assume not an Oracle Apps package and treat it as if it
2798 -- had an explicit AUTHID DEFINER clause.
2799
2800 open PKG_HEADER(owner, name, type);
2801
2802 fetch PKG_HEADER
2803 into header_string;
2804
2805 if PKG_HEADER%NOTFOUND then
2806 -- no header. Assume not an Oracle Apps pkg
2807
2808 close PKG_HEADER;
2809
2810 has_authid := 'TRUE';
2811 invoker_flag := 'D';
2812
2813 else
2814 -- has header. Assume an Oracle Apps pkg
2815
2816 close PKG_HEADER;
2817
2818 end if;
2819 -- end if pkg has valid Header string
2820
2821 end if;
2822 -- end if found AUTHID keyword
2823
2824 exception
2825 when others then
2826 ad_apps_private.error_buf := 'classify_plsql_object('
2827 || owner ||', '|| name ||', '|| type ||'): '||
2828 ad_apps_private.error_buf;
2829 raise;
2830 end classify_plsql_object;
2831
2832
2833 procedure classify_plsql_array
2834 (the_array in dbms_sql.varchar2s,
2835 lb in number,
2836 ub in number,
2837 type in varchar2,
2838 has_authid out nocopy varchar2,
2839 invoker_flag out nocopy varchar2)
2840 --
2841 -- Parses the PL/SQL source text stored in the varchar2s array
2842 --
2843 -- Sets has_authid to 'TRUE' if the object contains the AUTHID keyword
2844 -- sets has_authid to 'FALSE' otherwise
2845 --
2846 -- Sets invoker_flag to 'I' (Invoker's Rights; AUTHID CURRENT_USER)
2847 -- or 'D' (Definer's Rights; AUTHID DEFINER) if has_authid is 'TRUE'
2848 -- Sets invoker_flag to 'S' for Definer's Rights packages containing
2849 -- the /*nosync*/ comment (exactly as written, and delimited by whitespace)
2850 -- The /*nosync*/ comment must appear before the IS/AS keyword.
2851 --
2852 -- For wrapped package specs (procedures, functions), assumes definer's
2853 -- rights, as we really have no way to parse them. Not clear why anyone
2854 -- would want to wrap these objects, though...
2855 --
2856 -- 2/6/01 R Lotero
2857 --
2858 -- Deliberately don't add "customer hack" we added to classify_plsql_object.
2859 --
2860 -- This routine is only called from AD_DDL to create packages dynamically.
2861 -- In most cases dynamically-created packages should not contain Header
2862 -- strings because these are basically meaningless in a dynamically-created
2863 -- object. This means that even Oracle Apps dynamically-created packages
2864 -- should not contain Header strings, so the header -vs- no header
2865 -- distinction central to the "customer hack" is not useful for
2866 -- deciding if a given dynamically-created package belongs to Oracle Apps
2867 -- or to a customer.
2868 --
2869 is
2870 found_authid boolean;
2871 authid_line number;
2872 found_is_as boolean;
2873 found_wrapped boolean;
2874 is_as_line number;
2875 word_location number;
2876 is_as_position number;
2877 we_found_it varchar2(10);
2878 found_aid_type boolean;
2879 aid_type_line number;
2880 authid_type varchar2(10);
2881 found_nosync boolean;
2882 nosync_line number;
2883 begin
2884 -- Initialize return variables
2885
2886 has_authid := 'FALSE';
2887 invoker_flag := 'X';
2888
2889 -- Validate PL/SQL object type
2890
2891 if upper(type) <> 'PACKAGE'
2892 and upper(type) <> 'PROCEDURE'
2893 and upper(type) <> 'FUNCTION' then
2894
2895 raise_application_error(-20000,
2896 'Do not know how to classify objects of type "'||upper(type)||'".');
2897
2898 end if;
2899 -- end if not valid type
2900
2901 -- Initialize variables
2902
2903 found_authid := FALSE;
2904 found_is_as := FALSE;
2905 found_aid_type := FALSE;
2906 found_nosync := FALSE;
2907 found_wrapped := FALSE;
2908
2909 authid_line := 0;
2910 is_as_line := 0;
2911 aid_type_line := 0;
2912 nosync_line := 0;
2913
2914 --
2915 -- parse the source text
2916 --
2917 -- Exit loop when we find the IS/AS keyword
2918 --
2919
2920 for counter in lb..ub loop
2921
2922 -- Check for AUTHID
2923
2924 word_location := instr(upper(the_array(counter)),'AUTHID');
2925
2926 if word_location <> 0 then
2927
2928 -- Do more strict checking
2929
2930 verify_token_location(upper(the_array(counter)), 'AUTHID',
2931 we_found_it, word_location);
2932
2933 if we_found_it = 'TRUE' then
2934
2935 found_authid := TRUE;
2936 authid_line := counter;
2937
2938 end if;
2939 -- end if we really found AUTHID
2940
2941 end if;
2942 -- end if found AUTHID using INSTR
2943
2944 -- If found AUTHID, check for authid type
2945
2946 if found_authid then
2947
2948 -- Check for CURRENT_USER keyword
2949
2950 word_location := instr(upper(the_array(counter)),'CURRENT_USER');
2951
2952 if word_location <> 0 then
2953
2954 -- Do more strict checking
2955
2956 verify_token_location(upper(the_array(counter)), 'CURRENT_USER',
2957 we_found_it, word_location);
2958
2959 if we_found_it = 'TRUE' then
2960
2961 found_aid_type := TRUE;
2962 aid_type_line := counter;
2963 authid_type := 'I';
2964
2965 end if;
2966 -- end if we really found CURRENT_USER
2967
2968 end if;
2969 -- end if found CURRENT_USER using INSTR
2970
2971 -- Check for DEFINER keyword
2972
2973 word_location := instr(upper(the_array(counter)),'DEFINER');
2974
2975 if word_location <> 0 then
2976
2977 -- Do more strict checking
2978
2979 verify_token_location(upper(the_array(counter)), 'DEFINER',
2980 we_found_it, word_location);
2981
2982 if we_found_it = 'TRUE' then
2983
2984 found_aid_type := TRUE;
2985 aid_type_line := counter;
2986 authid_type := 'D';
2987
2988 end if;
2989 -- end if we really found DEFINER
2990
2991 end if;
2992 -- end if found DEFINER using INSTR
2993
2994 end if;
2995 -- end if check for AUTHID type
2996
2997 -- Check for /*nosync*/ comment
2998 -- Must be specified exactly as above (case-insensitive) and be
2999 -- delimited by whitespace
3000
3001 word_location := instr(upper(the_array(counter)),'/*NOSYNC*/');
3002
3003 if word_location <> 0 then
3004
3005 -- Do more strict checking
3006
3007 verify_token_location(upper(the_array(counter)), '/*NOSYNC*/',
3008 we_found_it, word_location);
3009
3010 if we_found_it = 'TRUE' then
3011
3012 found_nosync := TRUE;
3013 nosync_line := counter;
3014
3015 end if;
3016 -- end if we really found /*NOSYNC*/
3017
3018 end if;
3019 -- end if found /*NOSYNC*/ using INSTR
3020
3021 -- Check for AS
3022 -- Break out of the loop if we find it
3023
3024 word_location := instr(upper(the_array(counter)),'AS');
3025
3026 if word_location <> 0 then
3027
3028 -- Do more strict checking
3029
3030 verify_token_location(upper(the_array(counter)), 'AS',
3031 we_found_it, word_location);
3032
3033 if we_found_it = 'TRUE' then
3034
3035 found_is_as := TRUE;
3036 is_as_line := counter;
3037 exit;
3038
3039 end if;
3040 -- end if we really found AS
3041
3042 end if;
3043 -- end if found AS using INSTR
3044
3045 -- Check for IS
3046 -- Break out of the loop if we find it
3047
3048 word_location := instr(upper(the_array(counter)),'IS');
3049
3050 if word_location <> 0 then
3051
3052 -- Do more strict checking
3053
3054 verify_token_location(upper(the_array(counter)), 'IS',
3055 we_found_it, word_location);
3056
3057 if we_found_it = 'TRUE' then
3058
3059 found_is_as := TRUE;
3060 is_as_line := counter;
3061 exit;
3062
3063 end if;
3064 -- end if we really found IS
3065
3066 end if;
3067 -- end if found IS using INSTR
3068
3069 -- Check for WRAPPED
3070 -- Just make a note of it if we find it
3071
3072 word_location := instr(upper(the_array(counter)),'WRAPPED');
3073
3074 if word_location <> 0 then
3075
3076 -- Do more strict checking
3077
3078 verify_token_location(upper(the_array(counter)), 'WRAPPED',
3079 we_found_it, word_location);
3080
3081 if we_found_it = 'TRUE' then
3082
3083 found_wrapped := TRUE;
3084 is_as_line := counter;
3085 exit;
3086
3087 end if;
3088 -- end if we really found WRAPPED
3089
3090 end if;
3091 -- end if found WRAPPED using INSTR
3092
3093 end loop;
3094 -- end loop to parse source text
3095
3096 if not found_is_as then
3097
3098 -- Should only happen for wrapped package specs,
3099 -- wrapped procedures, or wrapped functions
3100
3101 if found_wrapped then
3102
3103 -- It's wierd to wrap a package spec, procedure, or function
3104 -- It's also annoying, because then we can't parse it to find
3105 -- out if it's invoker's rights or definer's rights.
3106 --
3107 -- Treat all wrapped specs, procedures, or functions as
3108 -- definer's rights objects. This is the safest strategy.
3109 --
3110
3111 has_authid := 'TRUE';
3112 invoker_flag := 'D';
3113 return;
3114
3115 else
3116
3117 --
3118 -- This should never happen, but it happens on Dev115
3119 -- Use the "safe" strategy from above: say it's Definer's Rights
3120 --
3121
3122 has_authid := 'TRUE';
3123 invoker_flag := 'D';
3124 return;
3125
3126 end if;
3127 -- end if found WRAPPED keyword
3128
3129 end if;
3130 -- end if didn't find IS/AS keyword
3131
3132 -- Set return values
3133
3134 if found_authid then
3135
3136 has_authid := 'TRUE';
3137
3138 if found_aid_type then
3139
3140 if authid_type = 'D' or authid_type = 'I' then
3141
3142 --
3143 -- Reset authid_type to 'S' for Definer's Rights objects
3144 -- that contain the /*nosync*/ comment
3145 --
3146 if authid_type = 'D' then
3147 if found_nosync then
3148 authid_type := 'S';
3149 end if;
3150 end if;
3151
3152 invoker_flag := authid_type;
3153 else
3154 raise_application_error(-20000,
3155 'Found AUTHID keyword, but did not find authid type');
3156 end if;
3157 -- end if valid authid type
3158
3159 end if;
3160 -- end if found authid type
3161
3162 end if;
3163 -- end if found AUTHID keyword
3164
3165 exception
3166 when others then
3167 ad_apps_private.error_buf := 'classify_plsql_array('
3168 || ' <array>, '|| lb ||', '|| ub ||', '|| type ||'): '||
3169 ad_apps_private.error_buf;
3170 raise;
3171 end classify_plsql_array;
3172
3173
3174 end ad_invoker;