1 PACKAGE BODY FND_OAM_DSCFG_COMPILER_PKG as
2 /* $Header: AFOAMDSCCOMPB.pls 120.8 2006/07/10 19:11:28 ilawler noship $ */
3
4 ----------------------------------------
5 -- Private Body Constants
6 ----------------------------------------
7 PKG_NAME CONSTANT VARCHAR2(20) := 'DSCFG_COMPILER_PKG.';
8
9 -- Defaults used when creating engine entities
10 B_DEFAULT_NUM_BUNDLES CONSTANT NUMBER := 1;
11 B_DEFAULT_RUN_MODE CONSTANT VARCHAR2(30) := FND_OAM_DSCRAM_UTILS_PKG.G_MODE_NORMAL;
12
13 --Pseudo-private state set and returned by public Getters
14 B_DEFAULT_WORKERS_ALLOWED NUMBER := NULL; -- set to MAX(#CPU-1,1) by first call to compile_config_instance
15 B_DEFAULT_BATCH_SIZE CONSTANT NUMBER := 10000;
16 B_DEFAULT_VALID_CHECK_INTERVAL CONSTANT NUMBER := 300; --5 minutes
17 -- # of blocks under which we don't parallelize, if NULL engine parallelizes everything with a weight.
18 -- NULL weights are always parallelized to be safe. 50 blocks corresponds to around 30k rows.
19 B_DEFAULT_MIN_PARALLEL_WEIGHT CONSTANT NUMBER := 50;
20
21 -- Constant used for DSCRAM Unit phases for various types of objects in a dependency group
22 B_PHASE_INCREMENT CONSTANT NUMBER := 10;
23 B_BASE_PHASE_TRUNCATES CONSTANT NUMBER := 1000000;
24 B_BASE_PHASE_UNBOUND_PLSQLS CONSTANT NUMBER := 2000000;
25 B_BASE_PHASE_BOUND_OPERATIONS CONSTANT NUMBER := 3000000;
26 B_BASE_PRIORITY_DELETES CONSTANT NUMBER := 100;
27 B_BASE_PRIORITY_BOUND_PLSQLS CONSTANT NUMBER := 200;
28 B_BASE_PRIORITY_UPDATES CONSTANT NUMBER := 300;
29
30 -- Default weight modifiers for various kinds of operations
31 -- TODO: these need some investigation
32 B_TRUNCATE_WEIGHT_MODIFIER CONSTANT NUMBER := .01;
33 B_DELETE_WEIGHT_MODIFIER CONSTANT NUMBER := 1.01; --according to explain plan cost, delete is a little more than a one column update
34
35 -- The maximum length of a generated SQL statement. This needs to be the max
36 -- varchar2 length - space typically used for adding AD Splitting clauses.
37 B_STMT_MAXLEN CONSTANT NUMBER := 3900;
38
39 ----------------------------------------
40 -- Private Body Variables
41 ----------------------------------------
42
43 --*****
44 --Types
45 --*****
46
47 -- List of numbers
48 TYPE b_number_list_type IS TABLE OF NUMBER;
49
50 -- List of domains
51 TYPE b_domain_list_type IS TABLE OF VARCHAR2(120);
52
53 -- Map of domains for easy lookup
54 TYPE b_domain_map_type IS TABLE OF BOOLEAN INDEX BY VARCHAR2(120);
55
56 -- Mapping from primary_domain name to list of object_ids with that primary domain
57 TYPE b_primary_domains_type IS TABLE OF b_number_list_type INDEX BY VARCHAR2(120);
58
59 -- A dependency group loosely maps to a task in the engine. The dependency group is a list of primary domains and additional
60 -- domains which overlap due to the definitions of the objects in these domains.
61 TYPE b_dependency_group_def_type IS RECORD
62 (
63 primary_domains b_domain_list_type := NULL,
64 additional_domains b_domain_map_type,
65 task_id NUMBER := NULL,
66 priority NUMBER := NULL,
67 weight NUMBER := NULL
68 );
69
70 -- Mapping from dependency_group_id to a record containing component primary domains/additional domains
71 TYPE b_dependency_groups_type IS TABLE OF b_dependency_group_def_type INDEX BY BINARY_INTEGER;
72
73 -- Mapping from domain name to owning dependency_group_id
74 TYPE b_domain_to_group_map_type IS TABLE OF NUMBER INDEX BY VARCHAR2(120);
75
76 -- Represents a DSCFG_PROPERTIES row.
77 TYPE b_property_def_type IS RECORD
78 (
79 property_id NUMBER := NULL,
80 property_name VARCHAR2(120) := NULL,
81 datatype VARCHAR2(30) := NULL,
82 canonical_value VARCHAR2(4000) := NULL
83 );
84 -- Table of properties, indexed by property_id.
85 TYPE b_properties_type IS TABLE OF b_property_def_type INDEX BY BINARY_INTEGER;
86
87 -- Represents a DSCFG_OBJECTS row. Records the type most importantly but also any top level, object metadata.
88 TYPE b_object_def_type IS RECORD
89 (
90 object_id NUMBER := NULL,
91 object_type VARCHAR2(30) := NULL,
92 target_type VARCHAR2(30) := NULL,
93 target_id NUMBER := NULL,
94 new_errors_found_flag VARCHAR2(3) := NULL,
95 new_message VARCHAR2(4000) := NULL, --new message to write to the object's message field
96 is_dirty BOOLEAN := FALSE, --determines if we need to write the object out
97 primary_domain VARCHAR2(120) := NULL,
98 additional_domains b_domain_list_type := NULL
99 --properties b_properties_type
100 );
101 -- master objects map, key=object_id, value = an object_def_type record. Exists as an indirect
102 -- to allow other structures to be type-agnostic by using object_ids that can be looked up in this
103 -- htable to determine the htable where the object's definition is stored based on the object_type.
104 TYPE b_objects_type IS TABLE OF b_object_def_type INDEX BY BINARY_INTEGER;
105
106 -- Record and Table types for DML_UPDATE_SEGMENT-typed objects.
107 TYPE b_dml_update_segment_def_type IS RECORD
108 (
109 table_owner VARCHAR2(30) := NULL,
110 table_name VARCHAR2(30) := NULL,
111 column_name VARCHAR2(30) := NULL,
112 new_column_value VARCHAR2(4000) := NULL,
113 where_clause VARCHAR2(4000) := NULL,
114 weight_modifier NUMBER := 1
115 );
116 TYPE b_dml_update_segments_type IS TABLE OF b_dml_update_segment_def_type INDEX BY BINARY_INTEGER;
117
118 -- Record and Table types for DML_DELETE-typed objects.
119 TYPE b_dml_delete_stmt_def_type IS RECORD
120 (
121 table_owner VARCHAR2(30) := NULL,
122 table_name VARCHAR2(30) := NULL,
123 where_clause VARCHAR2(4000) := NULL,
124 weight NUMBER := NULL
125 );
126 TYPE b_dml_delete_stmts_type IS TABLE OF b_dml_delete_stmt_def_type INDEX BY BINARY_INTEGER;
127
128 -- Record and Table types for DML_TRUNCATE-typed objects.
129 TYPE b_dml_truncate_stmt_def_type IS RECORD
130 (
131 table_owner VARCHAR2(30) := NULL,
132 table_name VARCHAR2(30) := NULL,
133 weight NUMBER := NULL
134 );
135 TYPE b_dml_truncate_stmts_type IS TABLE OF b_dml_truncate_stmt_def_type INDEX BY BINARY_INTEGER;
136
137 -- Record and Table types for PLSQL_TEXT-typed objects.
138 TYPE b_plsql_text_def_type IS RECORD
139 (
140 plsql_text VARCHAR2(4000) := NULL,
141 table_owner VARCHAR2(30) := NULL, --used for table-specific splittable pl/sqls
142 table_name VARCHAR2(30) := NULL,
143 weight NUMBER := NULL
144 );
145 TYPE b_plsql_texts_type IS TABLE OF b_plsql_text_def_type INDEX BY BINARY_INTEGER;
146
147 -- Holds metadata concering the dscram_run entity
148 TYPE b_run_type IS RECORD
149 (
150 object_id NUMBER := NULL,
151 run_id NUMBER := NULL,
152 run_mode VARCHAR2(30) := NULL,
153 valid_check_interval NUMBER := NULL,
154 num_bundles NUMBER := NULL,
155 weight NUMBER := NULL,
156 assigned_physical_weight NUMBER := 0
157 );
158
159 -- Holds metadata concering the dscram_bundle entity
160 TYPE b_bundle_def_type IS RECORD
161 (
162 bundle_id NUMBER := NULL,
163 target_hostname VARCHAR2(256) := NULL,
164 workers_allowed NUMBER := NULL,
165 batch_size NUMBER := NULL,
166 min_parallel_unit_weight NUMBER := NULL,
167 weight NUMBER := NULL,
168 assigned_physical_weight NUMBER := 0,
169 assigned_task_count NUMBER := 0
170 );
171 TYPE b_bundles_type IS TABLE OF b_bundle_def_type INDEX BY BINARY_INTEGER;
172
173 -- Holds metadata related to a particular domain
174 TYPE b_domain_metadata_type IS RECORD
175 (
176 -- TODO: allow domain_metadata to specify a target_hostname to allow user-driven task partitioning.
177 weight NUMBER := NULL,
178 priority NUMBER := NULL,
179 phase NUMBER := NULL,
180 workers_allowed NUMBER := NULL,
181 disable_splitting VARCHAR2(3) := NULL,
182 error_fatality_level VARCHAR2(30) := NULL,
183 batch_size NUMBER := NULL
184 );
185 -- Map from object_type(may be null) to domain_metadata record
186 TYPE b_domain_obj_metadata_map_type IS TABLE OF b_domain_metadata_type INDEX BY VARCHAR2(30);
187 -- Map from domain name to (Map of object types-> domain metadata). Allows us to stripe metadata by particular types of
188 -- objects.
189 TYPE b_domain_metadata_map_type IS TABLE OF b_domain_obj_metadata_map_type INDEX BY VARCHAR2(120);
190
191 -- Map from a host name to the bundle object_id that represents it
192 TYPE b_host_name_map_type IS TABLE OF NUMBER INDEX BY VARCHAR2(256);
193
194 -- Map from column_name -> object_id
195 TYPE b_column_name_map_type IS TABLE OF NUMBER INDEX BY VARCHAR2(30);
196
197 -- Map from where_clause -> map of column_name->object_id
198 TYPE b_where_clause_column_map_type IS TABLE OF b_column_name_map_type INDEX BY VARCHAR2(4000);
199
200 -- Map from where_clause -> list of object_ids
201 TYPE b_where_clause_map_type IS TABLE OF NUMBER INDEX BY VARCHAR2(4000);
202
203 -- Stores references to the various objects under a given table owner/name
204 TYPE b_table_objects_def_type IS RECORD
205 (
206 update_map b_where_clause_column_map_type,
207 delete_map b_where_clause_map_type,
208 plsqls b_number_list_type := b_number_list_type()
209 );
210
211 -- Map from table_name -> table_objects_def_type struct
212 TYPE b_table_name_map_type IS TABLE OF b_table_objects_def_type INDEX BY VARCHAR2(30);
213
214 -- Map from table_owner -> map from table_name->table_objects struct containing corresponding object_ids
215 TYPE b_table_bound_map_type IS TABLE OF b_table_name_map_type INDEX BY VARCHAR2(30);
216
217 --*********
218 --State
219 --*********
220
221 --b_config_instance_id NUMBER := NULL;
222 -- Package level hash-tables to store parsed data fetched from
223 b_objects b_objects_type;
224 b_dml_update_segments b_dml_update_segments_type;
225 b_dml_delete_stmts b_dml_delete_stmts_type;
226 b_dml_truncate_stmts b_dml_truncate_stmts_type;
227 b_plsql_texts b_plsql_texts_type;
228
229 b_primary_domains b_primary_domains_type;
230 b_domain_metadata_map b_domain_metadata_map_type;
231
232 b_dependency_groups b_dependency_groups_type;
233 b_domain_to_group_map b_domain_to_group_map_type; --transient, used while coalescing domains into dependency groups
234
235 b_run b_run_type;
236 b_bundles b_bundles_type;
237
238 b_host_name_map b_host_name_map_type;
239 ----------------------------------------
240 -- Public/Private Procedures/Functions
241 ----------------------------------------
242
243 -- Private, allocates a new property definition type
244 FUNCTION CREATE_PROPERTY_DEF(p_property_id IN NUMBER,
245 p_property_name IN VARCHAR2,
246 p_datatype IN VARCHAR2,
247 p_canonical_value IN VARCHAR2)
248 RETURN b_property_def_type
249 IS
250 l_property b_property_def_type;
251 BEGIN
252 l_property.property_id := p_property_id;
253 l_property.property_name := p_property_name;
254 l_property.datatype := p_datatype;
255 l_property.canonical_value := p_canonical_value;
256
257 RETURN l_property;
258 END;
259
260 -- Private, allocates a new object definition type
261 FUNCTION CREATE_OBJECT_DEF(p_object_id IN NUMBER,
262 p_object_type IN VARCHAR2,
263 p_target_type IN VARCHAR2 DEFAULT NULL,
264 p_target_id IN NUMBER DEFAULT NULL)
265 RETURN b_object_def_type
266 IS
267 l_object b_object_def_type;
268 BEGIN
269 l_object.object_id := p_object_id;
270 l_object.object_type := p_object_type;
271 l_object.target_type := p_target_type;
272 l_object.target_id := p_target_id;
273
274 RETURN l_object;
275 END;
276
277 -- Private, allocates a new property definition type
278 FUNCTION CREATE_DEPENDENCY_GROUP_DEF(p_primary_domain IN VARCHAR2)
279 RETURN b_dependency_group_def_type
280 IS
281 l_group b_dependency_group_def_type;
282 BEGIN
283 l_group.primary_domains := b_domain_list_type(p_primary_domain);
284
285 RETURN l_group;
286 END;
287
288 -- Private, allocates a new property definition type
289 FUNCTION CREATE_BUNDLE_DEF(p_target_hostname IN VARCHAR2)
290
291 RETURN b_bundle_def_type
292 IS
293 l_bundle b_bundle_def_type;
294 BEGIN
295 l_bundle.target_hostname := p_target_hostname;
296 l_bundle.workers_allowed := GET_DEFAULT_NUM_WORKERS;
297 l_bundle.batch_size := GET_DEFAULT_BATCH_SIZE;
298 l_bundle.min_parallel_unit_weight := GET_DFLT_MIN_PARALLEL_WEIGHT;
299
300 RETURN l_bundle;
301 END;
302
303 -- Private, allocates a new table_objects_type.
304 FUNCTION CREATE_TABLE_OBJECTS_DEF
305 RETURN b_table_objects_def_type
306 IS
307 l_table_objects b_table_objects_def_type;
308 BEGIN
309
310 RETURN l_table_objects;
311 END;
312
313 -- Private, attach an error message
314 PROCEDURE MARK_OBJECT_AS_ERRORED(px_object IN OUT NOCOPY b_object_def_type,
315 p_message IN VARCHAR2)
316 IS
317 BEGIN
318 px_object.new_errors_found_flag := FND_API.G_TRUE;
319 IF px_object.new_message IS NULL THEN
320 px_object.new_message := p_message;
321 ELSE
322 px_object.new_message := px_object.new_message||', '||p_message;
323 END IF;
324 px_object.is_dirty := TRUE;
325 RETURN;
326 END;
327
328 -- Private, attach an error message
329 PROCEDURE MARK_OBJECT_AS_ERRORED(p_object_id IN NUMBER,
330 p_message IN VARCHAR2)
331 IS
332 BEGIN
333 b_objects(p_object_id).new_errors_found_flag := FND_API.G_TRUE;
334 IF b_objects(p_object_id).new_message IS NULL THEN
335 b_objects(p_object_id).new_message := p_message;
336 ELSE
337 b_objects(p_object_id).new_message := b_objects(p_object_id).new_message||', '||p_message;
338 END IF;
339 b_objects(p_object_id).is_dirty := TRUE;
340 RETURN;
341 END;
342
343 -- Wrapper on other mark_object_as_errored calls for exceptions.
344 PROCEDURE MARK_OBJECT_AS_ERRORED(p_object_id IN NUMBER,
345 p_ctxt IN VARCHAR2,
346 p_error_code IN NUMBER,
347 p_error_msg IN VARCHAR2)
348 IS
349 l_msg VARCHAR2(4000);
350 BEGIN
351 l_msg := 'Exception: (Code('||p_error_code||'), Message("'||p_error_msg||'"))';
352 fnd_oam_debug.log(3, p_ctxt, l_msg);
353 l_msg := '['||p_ctxt||']'||l_msg;
354 MARK_OBJECT_AS_ERRORED(p_object_id,
355 l_msg);
356 END;
357
358 -- Private, attach a warning message
359 PROCEDURE MARK_OBJECT_WITH_WARNING(p_object_id IN NUMBER,
360 p_ctxt IN VARCHAR2,
361 p_message IN VARCHAR2)
362 IS
363 l_prefix VARCHAR2(30) := 'WARNING: ';
364 l_msg VARCHAR2(4000);
365 BEGIN
366 -- prepare the message
367 IF length(p_message) + length(l_prefix) < 4000 THEN
368 l_msg := l_prefix||p_message;
369 ELSE
370 l_msg := p_message;
371 END IF;
372 --don't log a level 3 because this is a common case.
373 fnd_oam_debug.log(1, p_ctxt, l_msg);
374
375 IF b_objects(p_object_id).new_message IS NULL THEN
376 b_objects(p_object_id).new_message := l_msg;
377 ELSE
378 b_objects(p_object_id).new_message := b_objects(p_object_id).new_message||', '||l_msg;
379 END IF;
380 b_objects(p_object_id).is_dirty := TRUE;
381
382 RETURN;
383 END;
384
385 -- Private, helper to the CACHE_<OBJECT_TYPE> procedures to handle properties
386 -- which are common by setting them in the object. Returns a boolean of whether the property was
387 -- handled sucessfully.
388 PROCEDURE HANDLE_INVALID_PROPERTY(p_ctxt IN VARCHAR2,
389 px_object IN OUT NOCOPY b_object_def_type,
390 px_prop IN OUT NOCOPY b_property_def_type,
391 p_error_code IN NUMBER,
392 p_error_msg IN VARCHAR2)
393 IS
394 l_msg VARCHAR2(4000);
395 BEGIN
396 l_msg := 'Invalid Property "'||px_prop.property_name||'"('||px_prop.property_id||'), Error: (Code('||p_error_code||'), Message("'||p_error_msg||'"))';
397 fnd_oam_debug.log(3, p_ctxt, l_msg);
398 MARK_OBJECT_AS_ERRORED(px_object,
399 l_msg);
400 END;
401
402 -- Private, used to mark an object as errored when an unknown property is seen. This can be made a warning but
403 -- for now it's an error to keep people from seeding attributes that are ignored by the engine.
404 PROCEDURE HANDLE_UNKNOWN_PROPERTY(p_ctxt IN VARCHAR2,
405 px_object IN OUT NOCOPY b_object_def_type,
406 px_prop IN OUT NOCOPY b_property_def_type)
407 IS
408 l_msg VARCHAR2(4000);
409 BEGIN
410 l_msg := 'Unrecognized Property: '||px_prop.property_name||'('||px_prop.property_id||')';
411 fnd_oam_debug.log(3, p_ctxt, l_msg);
412 --unrecognized property
413 MARK_OBJECT_AS_ERRORED(px_object,
414 l_msg);
415 END;
416
417 -- Private, helper to the CACHE_<OBJECT_TYPE> procedures to handle properties
418 -- which are common by setting them in the object. Returns a boolean of whether the property was
419 -- handled sucessfully.
420 FUNCTION HANDLE_COMMON_PROPERTY(px_object IN OUT NOCOPY b_object_def_type,
421 px_prop IN OUT NOCOPY b_property_def_type)
422 RETURN BOOLEAN
423 IS
424 l_ctxt VARCHAR2(60) := PKG_NAME||'HANDLE_COMMON_PROPERTY';
425 l_msg VARCHAR2(4000);
426 BEGIN
427 CASE px_prop.property_name
428 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_PRIMARY_DOMAIN THEN
429 --force all domains to be case insensitive
430 px_object.primary_domain := UPPER(TRIM(px_prop.canonical_value));
431
432 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_ADDITIONAL_DOMAIN THEN
433 --the additional domain can't be null
434 IF px_prop.canonical_value IS NULL THEN
435 l_msg := 'Additional Domain properties cannot have NULL values.';
436 fnd_oam_debug.log(3, l_ctxt, l_msg);
437 --unrecognized property
438 MARK_OBJECT_AS_ERRORED(px_object,
439 l_msg);
440 RETURN FALSE;
441 END IF;
442
443 --append the domain
444 fnd_oam_debug.log(1, l_ctxt, 'found additional_domain: '||px_prop.canonical_value);
445 IF px_object.additional_domains IS NOT NULL THEN
446 px_object.additional_domains.EXTEND;
447 px_object.additional_domains(px_object.additional_domains.COUNT) := UPPER(TRIM(px_prop.canonical_value));
448 ELSE
449 px_object.additional_domains := b_domain_list_type(UPPER(TRIM(px_prop.canonical_value)));
450 END IF;
451
452 ELSE
453 HANDLE_UNKNOWN_PROPERTY(l_ctxt,
454 px_object,
455 px_prop);
456 RETURN FALSE;
457 END CASE;
458
459 -- sucessfully handled
460 RETURN TRUE;
461 EXCEPTION
462 WHEN OTHERS THEN
463 HANDLE_INVALID_PROPERTY(l_ctxt,
464 px_object,
465 px_prop,
466 SQLCODE,
467 SQLERRM);
468 RETURN FALSE;
469 END;
470
471 -- Private, simple helper to get rid of extra spaces and the 'where' if present.
472 PROCEDURE CLEANUP_WHERE_CLAUSE(px_where_clause IN OUT NOCOPY VARCHAR2)
473 IS
474 l_str VARCHAR2(30);
475 BEGIN
476 px_where_clause := TRIM(px_where_clause);
477 IF UPPER(SUBSTR(px_where_clause, 1, 6)) = 'WHERE ' THEN
478 px_where_clause := SUBSTR(px_where_clause, 7);
479 END IF;
480 END;
481
482 -- Private, Helper to ADD_ENGINE_UNITS_FOR_DOMAIN to validate an object of type DML_UPDATE_SEGMENT.
483 -- Returns TRUE if valid.
484 FUNCTION VALIDATE_DML_UPDATE_SEGMENT(px_object IN OUT NOCOPY b_object_def_type,
485 p_segment IN b_dml_update_segment_def_type)
486 RETURN BOOLEAN
487 IS
488 l_ctxt VARCHAR2(60) := PKG_NAME||'VALIDATE_DML_UPDATE_SEGMENT';
489
490 l_valid BOOLEAN := TRUE;
491 BEGIN
492 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
493
494 --check for our properties, add messages for each not found
495 IF p_segment.table_owner IS NULL THEN
496 MARK_OBJECT_AS_ERRORED(px_object,
497 'Missing Property: '||FND_OAM_DSCFG_API_PKG.G_PROP_TABLE_OWNER);
498 l_valid := FALSE;
499 END IF;
500
501 IF p_segment.table_name IS NULL THEN
502 MARK_OBJECT_AS_ERRORED(px_object,
503 'Missing Property: '||FND_OAM_DSCFG_API_PKG.G_PROP_TABLE_NAME);
504 l_valid := FALSE;
505 END IF;
506
507 IF p_segment.column_name IS NULL THEN
508 MARK_OBJECT_AS_ERRORED(px_object,
509 'Missing Property: '||FND_OAM_DSCFG_API_PKG.G_PROP_COLUMN_NAME);
510 l_valid := FALSE;
511 END IF;
512
513 IF p_segment.new_column_value IS NULL THEN
514 MARK_OBJECT_AS_ERRORED(px_object,
515 'Missing Property: '||FND_OAM_DSCFG_API_PKG.G_PROP_NEW_COLUMN_VALUE);
516 l_valid := FALSE;
517 END IF;
518
519 fnd_oam_debug.log(1, l_ctxt, 'Verdict: '||FND_OAM_DSCFG_UTILS_PKG.BOOLEAN_TO_CANONICAL(l_valid));
520
521 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
522 RETURN l_valid;
523 EXCEPTION
524 WHEN OTHERS THEN
525 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
526 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
527 RAISE PROGRAM_ERROR;
528 END;
529
530 -- Private, helper to CACHE_OBJECT to cache an object of type DML_UPDATE_SEGMENT
531 --
532 PROCEDURE CACHE_DML_UPDATE_SEGMENT(px_object IN OUT NOCOPY b_object_def_type,
533 px_object_props IN OUT NOCOPY b_properties_type)
534 IS
535 l_ctxt VARCHAR2(60) := PKG_NAME||'CACHE_DML_UPDATE_SEGMENT';
536
537 l_dml_update_segment b_dml_update_segment_def_type;
538
539 k NUMBER;
540 l_prop b_property_def_type := NULL;
541 l_msg VARCHAR2(4000);
542 BEGIN
543 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
544
545 --loop through the object properties, filling in the details of the dml_update_segment
546 BEGIN
547 k := px_object_props.FIRST;
548 WHILE k IS NOT NULL LOOP
549 l_prop := px_object_props(k);
550
551 CASE l_prop.property_name
552 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_TABLE_OWNER THEN
553 l_dml_update_segment.table_owner := l_prop.canonical_value;
554
555 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_TABLE_NAME THEN
556 l_dml_update_segment.table_name := l_prop.canonical_value;
557
558 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_COLUMN_NAME THEN
559 l_dml_update_segment.column_name := l_prop.canonical_value;
560
561 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_NEW_COLUMN_VALUE THEN
562 l_dml_update_segment.new_column_value := l_prop.canonical_value;
563
564 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_WHERE_CLAUSE THEN
565 l_dml_update_segment.where_clause := l_prop.canonical_value;
566
567 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_WEIGHT_MODIFIER THEN
568 l_dml_update_segment.weight_modifier := FND_OAM_DSCFG_UTILS_PKG.CANONICAL_TO_NUMBER(l_prop.canonical_value);
569
570 ELSE
571 --defer to the common handler if none of the object_type-specific property names match.
572 IF NOT HANDLE_COMMON_PROPERTY(px_object,
573 l_prop) THEN
574 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
575 RETURN;
576 END IF;
577 END CASE;
578
579 k := px_object_props.NEXT(k);
580 END LOOP;
581 EXCEPTION
582 WHEN OTHERS THEN
583 -- covers character string buffer too small
584 HANDLE_INVALID_PROPERTY(l_ctxt,
585 px_object,
586 l_prop,
587 SQLCODE,
588 SQLERRM);
589 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
590 RETURN;
591 END;
592
593 -- only cache it if it's valid
594 IF VALIDATE_DML_UPDATE_SEGMENT(px_object,
595 l_dml_update_segment) THEN
596
597 --if it's valid, do some cleanup
598 l_dml_update_segment.table_owner := UPPER(TRIM(l_dml_update_segment.table_owner));
599 l_dml_update_segment.table_name := UPPER(TRIM(l_dml_update_segment.table_name));
600 IF l_dml_update_segment.where_clause IS NOT NULL THEN
601 CLEANUP_WHERE_CLAUSE(l_dml_update_segment.where_clause);
602 END IF;
603
604 --default the primary_domain using the table_owner.table_name if not specified as a property
605 IF px_object.primary_domain IS NULL THEN
606 px_object.primary_domain := l_dml_update_segment.table_owner||'.'||l_dml_update_segment.table_name;
607 END IF;
608
609 --put it in the dml_update_segments cache
610 b_dml_update_segments(px_object.object_id) := l_dml_update_segment;
611 END IF;
612
613 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
614 EXCEPTION
615 WHEN PROGRAM_ERROR THEN
616 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
617 RAISE;
618 WHEN OTHERS THEN
619 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
620 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
621 RAISE PROGRAM_ERROR;
622 END;
623
624 -- Private, Helper to ADD_ENGINE_UNITS_FOR_DOMAIN to validate an object of type DML_DELETE_STMT
625 -- Returns TRUE if valid.
626 FUNCTION VALIDATE_DML_DELETE_STMT(px_object IN OUT NOCOPY b_object_def_type,
627 p_stmt IN b_dml_delete_stmt_def_type)
628 RETURN BOOLEAN
629 IS
630 l_ctxt VARCHAR2(60) := PKG_NAME||'VALIDATE_DML_DELETE_STMT';
631
632 l_valid BOOLEAN := TRUE;
633 BEGIN
634 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
635
636 --check for our properties, add messages for each not found
637 IF p_stmt.table_owner IS NULL THEN
638 MARK_OBJECT_AS_ERRORED(px_object,
639 'Missing Property: '||FND_OAM_DSCFG_API_PKG.G_PROP_TABLE_OWNER);
640 l_valid := FALSE;
641 END IF;
642
643 IF p_stmt.table_name IS NULL THEN
644 MARK_OBJECT_AS_ERRORED(px_object,
645 'Missing Property: '||FND_OAM_DSCFG_API_PKG.G_PROP_TABLE_NAME);
646 l_valid := FALSE;
647 END IF;
648
649 fnd_oam_debug.log(1, l_ctxt, 'Verdict: '||FND_OAM_DSCFG_UTILS_PKG.BOOLEAN_TO_CANONICAL(l_valid));
650
651 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
652 RETURN l_valid;
653 EXCEPTION
654 WHEN OTHERS THEN
655 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
656 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
657 RAISE PROGRAM_ERROR;
658 END;
659
660 -- Private, helper to CACHE_OBJECT to cache an object of type DML_DELETE_STMT
661 --
662 PROCEDURE CACHE_DML_DELETE_STMT(px_object IN OUT NOCOPY b_object_def_type,
663 px_object_props IN OUT NOCOPY b_properties_type)
664 IS
665 l_ctxt VARCHAR2(60) := PKG_NAME||'CACHE_DML_DELETE_STMT';
666
667 l_dml_delete_stmt b_dml_delete_stmt_def_type;
668
669 k NUMBER;
670 l_prop b_property_def_type := NULL;
671 l_msg VARCHAR2(4000);
672 BEGIN
673 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
674
675 --loop through the object properties, filling in the details of the dml_delete_stmt
676 BEGIN
677 k := px_object_props.FIRST;
678 WHILE k IS NOT NULL LOOP
679 l_prop := px_object_props(k);
680
681 CASE l_prop.property_name
682 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_TABLE_OWNER THEN
683 l_dml_delete_stmt.table_owner := l_prop.canonical_value;
684
685 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_TABLE_NAME THEN
686 l_dml_delete_stmt.table_name := l_prop.canonical_value;
687
688 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_WHERE_CLAUSE THEN
689 l_dml_delete_stmt.where_clause := l_prop.canonical_value;
690
691 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_WEIGHT THEN
692 l_dml_delete_stmt.weight := FND_OAM_DSCFG_UTILS_PKG.CANONICAL_TO_NUMBER(l_prop.canonical_value);
693
694 ELSE
695 --defer to the common handler if none of the object_type-specific property names match.
696 IF NOT HANDLE_COMMON_PROPERTY(px_object,
697 l_prop) THEN
698 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
699 RETURN;
700 END IF;
701 END CASE;
702
703 k := px_object_props.NEXT(k);
704 END LOOP;
705 EXCEPTION
706 WHEN OTHERS THEN
707 -- covers character string buffer too small
708 HANDLE_INVALID_PROPERTY(l_ctxt,
709 px_object,
710 l_prop,
711 SQLCODE,
712 SQLERRM);
713 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
714 RETURN;
715 END;
716
717 -- only cache it if it's valid
718 IF VALIDATE_DML_DELETE_STMT(px_object,
719 l_dml_delete_stmt) THEN
720
721 --if it's valid, do some cleanup
722 l_dml_delete_stmt.table_owner := UPPER(TRIM(l_dml_delete_stmt.table_owner));
723 l_dml_delete_stmt.table_name := UPPER(TRIM(l_dml_delete_stmt.table_name));
724 IF l_dml_delete_stmt.where_clause IS NOT NULL THEN
725 CLEANUP_WHERE_CLAUSE(l_dml_delete_stmt.where_clause);
726 END IF;
727
728 --default the primary_domain using the table_owner.table_name if not specified as a property
729 IF px_object.primary_domain IS NULL THEN
730 px_object.primary_domain := l_dml_delete_stmt.table_owner||'.'||l_dml_delete_stmt.table_name;
731 END IF;
732
733 --put it in the dml_delete_stmts cache
734 b_dml_delete_stmts(px_object.object_id) := l_dml_delete_stmt;
735 END IF;
736
737 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
738 EXCEPTION
739 WHEN PROGRAM_ERROR THEN
740 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
741 RAISE;
742 WHEN OTHERS THEN
743 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
744 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
745 RAISE PROGRAM_ERROR;
746 END;
747
748 -- Private, Helper to ADD_ENGINE_UNITS_FOR_DOMAIN to validate an object of type DML_TRUNCATE_STMT
749 -- Returns TRUE if valid.
750 FUNCTION VALIDATE_DML_TRUNCATE_STMT(px_object IN OUT NOCOPY b_object_def_type,
751 p_stmt IN b_dml_truncate_stmt_def_type)
752 RETURN BOOLEAN
753 IS
754 l_ctxt VARCHAR2(60) := PKG_NAME||'VALIDATE_DML_TRUNCATE_STMT';
755
756 l_valid BOOLEAN := TRUE;
757 BEGIN
758 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
759
760 --check for our properties, add messages for each not found
761 IF p_stmt.table_owner IS NULL THEN
762 MARK_OBJECT_AS_ERRORED(px_object,
763 'Missing Property: '||FND_OAM_DSCFG_API_PKG.G_PROP_TABLE_OWNER);
764 l_valid := FALSE;
765 END IF;
766
767 IF p_stmt.table_name IS NULL THEN
768 MARK_OBJECT_AS_ERRORED(px_object,
769 'Missing Property: '||FND_OAM_DSCFG_API_PKG.G_PROP_TABLE_NAME);
770 l_valid := FALSE;
771 END IF;
772
773 fnd_oam_debug.log(1, l_ctxt, 'Verdict: '||FND_OAM_DSCFG_UTILS_PKG.BOOLEAN_TO_CANONICAL(l_valid));
774
775 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
776 RETURN l_valid;
777 EXCEPTION
778 WHEN OTHERS THEN
779 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
780 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
781 RAISE PROGRAM_ERROR;
782 END;
783
784 -- Private, helper to CACHE_OBJECT to cache an object of type DML_TRUNCATE_STMT
785 --
786 PROCEDURE CACHE_DML_TRUNCATE_STMT(px_object IN OUT NOCOPY b_object_def_type,
787 px_object_props IN OUT NOCOPY b_properties_type)
788 IS
789 l_ctxt VARCHAR2(60) := PKG_NAME||'CACHE_DML_TRUNCATE_STMT';
790
791 l_dml_truncate_stmt b_dml_truncate_stmt_def_type;
792
793 k NUMBER;
794 l_prop b_property_def_type := NULL;
795 l_msg VARCHAR2(4000);
796 BEGIN
797 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
798
799 --loop through the object properties, filling in the details of the dml_truncate_stmt
800 BEGIN
801 k := px_object_props.FIRST;
802 WHILE k IS NOT NULL LOOP
803 l_prop := px_object_props(k);
804
805 CASE l_prop.property_name
806 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_TABLE_OWNER THEN
807 l_dml_truncate_stmt.table_owner := l_prop.canonical_value;
808
809 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_TABLE_NAME THEN
810 l_dml_truncate_stmt.table_name := l_prop.canonical_value;
811
812 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_WEIGHT THEN
813 l_dml_truncate_stmt.weight := FND_OAM_DSCFG_UTILS_PKG.CANONICAL_TO_NUMBER(l_prop.canonical_value);
814
815 ELSE
816 --defer to the common handler if none of the object_type-specific property names match.
817 IF NOT HANDLE_COMMON_PROPERTY(px_object,
818 l_prop) THEN
819 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
820 RETURN;
821 END IF;
822 END CASE;
823
824 k := px_object_props.NEXT(k);
825 END LOOP;
826 EXCEPTION
827 WHEN OTHERS THEN
828 -- covers character string buffer too small
829 HANDLE_INVALID_PROPERTY(l_ctxt,
830 px_object,
831 l_prop,
832 SQLCODE,
833 SQLERRM);
834 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
835 RETURN;
836 END;
837
838 -- only cache it if it's valid
839 IF VALIDATE_DML_TRUNCATE_STMT(px_object,
840 l_dml_truncate_stmt) THEN
841
842 --if it's valid, do some cleanup
843 l_dml_truncate_stmt.table_owner := UPPER(TRIM(l_dml_truncate_stmt.table_owner));
844 l_dml_truncate_stmt.table_name := UPPER(TRIM(l_dml_truncate_stmt.table_name));
845
846 --default the primary_domain using the table_owner.table_name if not specified as a property
847 IF px_object.primary_domain IS NULL THEN
848 px_object.primary_domain := l_dml_truncate_stmt.table_owner||'.'||l_dml_truncate_stmt.table_name;
849 END IF;
850
851 --put it in the dml_truncate_stmts cache
852 b_dml_truncate_stmts(px_object.object_id) := l_dml_truncate_stmt;
853 END IF;
854
855 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
856 EXCEPTION
857 WHEN PROGRAM_ERROR THEN
858 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
859 RAISE;
860 WHEN OTHERS THEN
861 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
862 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
863 RAISE PROGRAM_ERROR;
864 END;
865
866 -- Private, Helper to ADD_ENGINE_UNITS_FOR_DOMAIN to validate an object of type PLSQL_TEXT
867 -- Returns TRUE if valid.
868 FUNCTION VALIDATE_PLSQL_TEXT(px_object IN OUT NOCOPY b_object_def_type,
869 p_plsql IN b_plsql_text_def_type)
870 RETURN BOOLEAN
871 IS
872 l_ctxt VARCHAR2(60) := PKG_NAME||'VALIDATE_PLSQL_TEXT';
873
874 l_valid BOOLEAN := TRUE;
875 BEGIN
876 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
877
878 --check for our properties, add messages for each not found
879 IF p_plsql.plsql_text IS NULL THEN
880 MARK_OBJECT_AS_ERRORED(px_object,
881 'Missing Property: '||FND_OAM_DSCFG_API_PKG.G_PROP_PLSQL_TEXT);
882 l_valid := FALSE;
883 END IF;
884
885 fnd_oam_debug.log(1, l_ctxt, 'Verdict: '||FND_OAM_DSCFG_UTILS_PKG.BOOLEAN_TO_CANONICAL(l_valid));
886
887 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
888 RETURN l_valid;
889 EXCEPTION
890 WHEN OTHERS THEN
891 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
892 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
893 RAISE PROGRAM_ERROR;
894 END;
895
896 -- Private, helper to CACHE_OBJECT to cache an object of type PLSQL_TEXT
897 --
898 PROCEDURE CACHE_PLSQL_TEXT(px_object IN OUT NOCOPY b_object_def_type,
899 px_object_props IN OUT NOCOPY b_properties_type)
900 IS
901 l_ctxt VARCHAR2(60) := PKG_NAME||'CACHE_PLSQL_TEXT';
902
903 l_plsql_text b_plsql_text_def_type;
904
905 k NUMBER;
906 l_prop b_property_def_type := NULL;
907 l_msg VARCHAR2(4000);
908 BEGIN
909 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
910
911 --loop through the object properties, filling in the details of the plsql_text
912 BEGIN
913 k := px_object_props.FIRST;
914 WHILE k IS NOT NULL LOOP
915 l_prop := px_object_props(k);
916
917 CASE l_prop.property_name
918 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_PLSQL_TEXT THEN
919 l_plsql_text.plsql_text := l_prop.canonical_value;
920
921 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_TABLE_OWNER THEN
922 l_plsql_text.table_owner := l_prop.canonical_value;
923
924 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_TABLE_NAME THEN
925 l_plsql_text.table_name := l_prop.canonical_value;
926
927 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_WEIGHT THEN
928 l_plsql_text.weight := FND_OAM_DSCFG_UTILS_PKG.CANONICAL_TO_NUMBER(l_prop.canonical_value);
929
930 ELSE
931 --defer to the common handler if none of the object_type-specific property names match.
932 IF NOT HANDLE_COMMON_PROPERTY(px_object,
933 l_prop) THEN
934 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
935 RETURN;
936 END IF;
937 END CASE;
938
939 k := px_object_props.NEXT(k);
940 END LOOP;
941 EXCEPTION
942 WHEN OTHERS THEN
943 -- covers character string buffer too small
944 HANDLE_INVALID_PROPERTY(l_ctxt,
945 px_object,
946 l_prop,
947 SQLCODE,
948 SQLERRM);
949 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
950 RETURN;
951 END;
952
953 -- only cache it if it's valid
954 IF VALIDATE_PLSQL_TEXT(px_object,
955 l_plsql_text) THEN
956
957 -- try to default the primary_domain using the table_owner/name if specified
958 IF px_object.primary_domain IS NULL THEN
959 IF l_plsql_text.table_owner IS NOT NULL AND l_plsql_text.table_name IS NOT NULL THEN
960 px_object.primary_domain := l_plsql_text.table_owner||'.'||l_plsql_text.table_name;
961 END IF;
962 END IF;
963
964 --put it in the plsql_texts cache
965 b_plsql_texts(px_object.object_id) := l_plsql_text;
966 END IF;
967
968 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
969 EXCEPTION
970 WHEN PROGRAM_ERROR THEN
971 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
972 RAISE;
973 WHEN OTHERS THEN
974 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
975 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
976 RAISE PROGRAM_ERROR;
977 END;
978
979 -- Private, helper to CACHE_OBJECT to cache the run metadata information
980 --
981 PROCEDURE CACHE_RUN(px_object IN OUT NOCOPY b_object_def_type,
982 px_object_props IN OUT NOCOPY b_properties_type)
983 IS
984 l_ctxt VARCHAR2(60) := PKG_NAME||'CACHE_RUN';
985
986 k NUMBER;
987 l_prop b_property_def_type := NULL;
988 l_msg VARCHAR2(4000);
989 BEGIN
990 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
991
992 --if we've already initialized the run metadata, this object is invalid, we need only one
993 --run metadata entry per config instance
994 IF b_run.object_id IS NOT NULL THEN
995 l_msg := 'Run Metadata already defined by Object ID: "'||b_run.object_id||'"';
996 fnd_oam_debug.log(3, l_ctxt, l_msg);
997 MARK_OBJECT_AS_ERRORED(px_object,
998 l_msg);
999 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1000 RETURN;
1001 END IF;
1002
1003 --loop through the object properties, filling in the details of the run object
1004 BEGIN
1005 k := px_object_props.FIRST;
1006 WHILE k IS NOT NULL LOOP
1007 l_prop := px_object_props(k);
1008
1009 CASE l_prop.property_name
1010 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_RUN_ID THEN
1011 b_run.run_id := FND_OAM_DSCFG_UTILS_PKG.CANONICAL_TO_NUMBER(l_prop.canonical_value);
1012
1013 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_RUN_MODE THEN
1014 b_run.run_mode := l_prop.canonical_value;
1015
1016 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_VALID_CHECK_INTERVAL THEN
1017 b_run.valid_check_interval := FND_OAM_DSCFG_UTILS_PKG.CANONICAL_TO_NUMBER(l_prop.canonical_value);
1018
1019 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_NUM_BUNDLES THEN
1020 b_run.num_bundles := FND_OAM_DSCFG_UTILS_PKG.CANONICAL_TO_NUMBER(l_prop.canonical_value);
1021
1022 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_WEIGHT THEN
1023 b_run.weight := FND_OAM_DSCFG_UTILS_PKG.CANONICAL_TO_NUMBER(l_prop.canonical_value);
1024
1025 ELSE
1026 --invalid property
1027 HANDLE_UNKNOWN_PROPERTY(l_ctxt,
1028 px_object,
1029 l_prop);
1030 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1031 RETURN;
1032 END CASE;
1033
1034 k := px_object_props.NEXT(k);
1035 END LOOP;
1036 EXCEPTION
1037 WHEN OTHERS THEN
1038 -- covers character string buffer too small
1039 HANDLE_INVALID_PROPERTY(l_ctxt,
1040 px_object,
1041 l_prop,
1042 SQLCODE,
1043 SQLERRM);
1044 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1045 RETURN;
1046 END;
1047
1048 --defer validation until the GENERATE-phase because we need to have read in all objects to
1049 --get definitive answers.
1050
1051 --set the object_id to mark that we've seen runtime metadata
1052 b_run.object_id := px_object.object_id;
1053
1054 --success
1055 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1056 RETURN;
1057 EXCEPTION
1058 WHEN OTHERS THEN
1059 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
1060 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1061 RAISE PROGRAM_ERROR;
1062 END;
1063
1064 -- Private, helper to CACHE_OBJECT to cache the metadata for a bundle
1065 --
1066 PROCEDURE CACHE_BUNDLE(px_object IN OUT NOCOPY b_object_def_type,
1067 px_object_props IN OUT NOCOPY b_properties_type)
1068 IS
1069 l_ctxt VARCHAR2(60) := PKG_NAME||'CACHE_BUNDLE';
1070
1071 l_bundle b_bundle_def_type;
1072
1073 k NUMBER;
1074 l_prop b_property_def_type := NULL;
1075 l_msg VARCHAR2(4000);
1076 BEGIN
1077 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
1078
1079 --if we've already seen run.num_bundles of bundles, this one is too many
1080 IF b_run.num_bundles IS NOT NULL AND b_run.num_bundles = b_bundles.COUNT THEN
1081 l_msg := 'Already seen expected number of bundles: "'||b_run.num_bundles||'".';
1082 fnd_oam_debug.log(3, l_ctxt, l_msg);
1083 MARK_OBJECT_AS_ERRORED(px_object,
1084 l_msg);
1085 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1086 RETURN;
1087 END IF;
1088
1089 --loop through the object properties, filling in the details of the run object
1090 BEGIN
1091 k := px_object_props.FIRST;
1092 WHILE k IS NOT NULL LOOP
1093 l_prop := px_object_props(k);
1094
1095 CASE l_prop.property_name
1096 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_BUNDLE_ID THEN
1097 l_bundle.bundle_id := FND_OAM_DSCFG_UTILS_PKG.CANONICAL_TO_NUMBER(l_prop.canonical_value);
1098
1099 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_TARGET_HOSTNAME THEN
1100 l_bundle.target_hostname := UPPER(l_prop.canonical_value);
1101
1102 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_WORKERS_ALLOWED THEN
1103 l_bundle.workers_allowed := FND_OAM_DSCFG_UTILS_PKG.CANONICAL_TO_NUMBER(l_prop.canonical_value);
1104
1105 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_BATCH_SIZE THEN
1106 l_bundle.batch_size := FND_OAM_DSCFG_UTILS_PKG.CANONICAL_TO_NUMBER(l_prop.canonical_value);
1107
1108 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_MIN_PARALLEL_WEIGHT THEN
1109 l_bundle.min_parallel_unit_weight := FND_OAM_DSCFG_UTILS_PKG.CANONICAL_TO_NUMBER(l_prop.canonical_value);
1110
1111 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_WEIGHT THEN
1112 l_bundle.weight := FND_OAM_DSCFG_UTILS_PKG.CANONICAL_TO_NUMBER(l_prop.canonical_value);
1113
1114 ELSE
1115 --invalid property
1116 HANDLE_UNKNOWN_PROPERTY(l_ctxt,
1117 px_object,
1118 l_prop);
1119 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1120 RETURN;
1121 END CASE;
1122
1123 k := px_object_props.NEXT(k);
1124 END LOOP;
1125 EXCEPTION
1126 WHEN OTHERS THEN
1127 -- covers character string buffer too small
1128 HANDLE_INVALID_PROPERTY(l_ctxt,
1129 px_object,
1130 l_prop,
1131 SQLCODE,
1132 SQLERRM);
1133 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1134 RETURN;
1135 END;
1136
1137 --defer validation until the GENERATE-phase because we need to have read in all objects to
1138 --get definitive answers.
1139
1140 --add the bundle to the bundles list
1141 b_bundles(px_object.object_id) := l_bundle;
1142
1143 --success
1144 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1145 RETURN;
1146 EXCEPTION
1147 WHEN OTHERS THEN
1148 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
1149 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1150 RAISE PROGRAM_ERROR;
1151 END;
1152
1153 /*
1154 --TODO:
1155 -- Private, helper to CACHE_OBJECT to cache the metadata for a domain
1156 --
1157 PROCEDURE CACHE_DOMAIN_METADATA(px_object IN OUT NOCOPY b_object_def_type,
1158 px_object_props IN OUT NOCOPY b_properties_type)
1159 IS
1160 l_ctxt VARCHAR2(60) := PKG_NAME||'CACHE_DOMAIN_METADATA';
1161
1162 l_domain VARCHAR2(120) := NULL;
1163 l_table_owner VARCHAR2(30) := NULL;
1164 l_table_name VARCHAR2(30) := NULL;
1165 l_object_type VARCHAR2(30) := NULL;
1166 l_domain_metadata b_domain_metadata_type;
1167 l_domain_obj_metadata_map b_domain_obj_metadata_map_type;
1168
1169 k NUMBER;
1170 l_prop b_property_def_type := NULL;
1171 l_msg VARCHAR2(4000);
1172 BEGIN
1173 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
1174
1175 --loop through the object properties, filling in the details of the run object
1176 BEGIN
1177 k := px_object_props.FIRST;
1178 WHILE k IS NOT NULL LOOP
1179 l_prop := px_object_props(k);
1180
1181 CASE l_prop.property_name
1182 WHEN FND_OAM_DSCFG_API_PKG.G_PROP_WEIGHT THEN
1183 l_bundle.weight := FND_OAM_DSCFG_UTILS_PKG.CANONICAL_TO_NUMBER(l_prop.canonical_value);
1184
1185 ELSE
1186 --invalid property
1187 HANDLE_UNKNOWN_PROPERTY(l_ctxt,
1188 px_object,
1189 l_prop);
1190 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1191 RETURN;
1192 END CASE;
1193
1194 k := px_object_props.NEXT(k);
1195 END LOOP;
1196 EXCEPTION
1197 WHEN OTHERS THEN
1198 -- covers character string buffer too small
1199 HANDLE_INVALID_PROPERTY(l_ctxt,
1200 px_object,
1201 l_prop,
1202 SQLCODE,
1203 SQLERRM);
1204 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1205 RETURN;
1206 END;
1207
1208 --add the bundle to the bundles list
1209 --b_bundles(px_object.object_id) := l_bundle;
1210
1211 --success
1212 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1213 RETURN;
1214 EXCEPTION
1215 WHEN OTHERS THEN
1216 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
1217 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1218 RAISE;
1219 END;
1220 */
1221 -- Private, used by FETCH_COMPILABLE_OBJECTS to put a new object into the various
1222 -- package caches
1223 PROCEDURE CACHE_OBJECT(px_object IN OUT NOCOPY b_object_def_type,
1224 px_object_props IN OUT NOCOPY b_properties_type)
1225 IS
1226 l_ctxt VARCHAR2(60) := PKG_NAME||'CACHE_OBJECT';
1227
1228 l_number_list b_number_list_type;
1229 l_msg VARCHAR2(4000);
1230 BEGIN
1231 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
1232
1233 --prepare the object and cache it in the object_type-specific cache
1234 CASE px_object.object_type
1235 WHEN FND_OAM_DSCFG_API_PKG.G_OTYPE_DML_UPDATE_SEGMENT THEN
1236 CACHE_DML_UPDATE_SEGMENT(px_object,
1237 px_object_props);
1238 WHEN FND_OAM_DSCFG_API_PKG.G_OTYPE_DML_DELETE_STMT THEN
1239 CACHE_DML_DELETE_STMT(px_object,
1240 px_object_props);
1241 WHEN FND_OAM_DSCFG_API_PKG.G_OTYPE_DML_TRUNCATE_STMT THEN
1242 CACHE_DML_TRUNCATE_STMT(px_object,
1243 px_object_props);
1244 WHEN FND_OAM_DSCFG_API_PKG.G_OTYPE_PLSQL_TEXT THEN
1245 CACHE_PLSQL_TEXT(px_object,
1246 px_object_props);
1247 WHEN FND_OAM_DSCFG_API_PKG.G_OTYPE_RUN THEN
1248 CACHE_RUN(px_object,
1249 px_object_props);
1250 WHEN FND_OAM_DSCFG_API_PKG.G_OTYPE_BUNDLE THEN
1251 CACHE_BUNDLE(px_object,
1252 px_object_props);
1253 --WHEN FND_OAM_DSCFG_API_PKG.G_OTYPE_DOMAIN_METADATA THEN
1254 -- CACHE_DOMAIN_METADATA(px_object,
1255 -- px_object_props);
1256 ELSE
1257 --unknown object type, add a message, set the errors flag
1258 l_msg := 'Object Type: "'||px_object.object_type||'" not supported';
1259 fnd_oam_debug.log(3, l_ctxt, l_msg);
1260 MARK_OBJECT_AS_ERRORED(px_object,
1261 l_msg);
1262 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1263 RETURN;
1264 END CASE;
1265
1266 --check that the object came back with a primary domain
1267 IF px_object.primary_domain IS NULL AND
1268 px_object.object_type NOT IN (FND_OAM_DSCFG_API_PKG.G_OTYPE_RUN,
1269 FND_OAM_DSCFG_API_PKG.G_OTYPE_BUNDLE) THEN
1270 l_msg := 'Object has no primary domain - this is not allowed.';
1271 fnd_oam_debug.log(3, l_ctxt, l_msg);
1272 MARK_OBJECT_AS_ERRORED(px_object,
1273 l_msg);
1274 END IF;
1275
1276 --store the object in the b_objects cache in any case
1277 b_objects(px_object.object_id) := px_object;
1278
1279 --so we don't have to traverse the object list right after this, go ahead and add this object to
1280 --the primary domains cache if it hasn't errored out yet.
1281 IF px_object.new_errors_found_flag IS NULL AND px_object.primary_domain IS NOT NULL THEN
1282 fnd_oam_debug.log(1, l_ctxt, 'Caching valid primary_domain('||px_object.primary_domain||'), object_id('||px_object.object_id||')');
1283 IF b_primary_domains.EXISTS(px_object.primary_domain) THEN
1284 --add this object_id
1285 b_primary_domains(px_object.primary_domain).EXTEND;
1286 b_primary_domains(px_object.primary_domain)(b_primary_domains(px_object.primary_domain).COUNT) := px_object.object_id;
1287 ELSE
1288 --new number list
1289 l_number_list := b_number_list_type(px_object.object_id);
1290 b_primary_domains(px_object.primary_domain) := l_number_list;
1291 END IF;
1292 END IF;
1293
1294 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1295 EXCEPTION
1296 WHEN PROGRAM_ERROR THEN
1297 --any errors in the CACHE_<OBJECT_TYPE> come up to this level as program_errors, catch them and swallow
1298 --so we can work try other objects
1299 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1300 RETURN;
1301 WHEN OTHERS THEN
1302 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
1303 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1304 RAISE PROGRAM_ERROR;
1305 END;
1306
1307 -- Private
1308 -- Helper to compile_config_instance to query out all objects
1309 PROCEDURE FETCH_COMPILABLE_OBJECTS(p_config_instance_id IN NUMBER)
1310 IS
1311 l_ctxt VARCHAR2(60) := PKG_NAME||'FETCH_COMPILABLE_OBJECTS';
1312
1313 -- temp variables for bulk collecting objects
1314 l_object_ids DBMS_SQL.NUMBER_TABLE;
1315 l_object_types DBMS_SQL.VARCHAR2_TABLE;
1316 l_target_types DBMS_SQL.VARCHAR2_TABLE;
1317 l_target_ids DBMS_SQL.NUMBER_TABLE;
1318
1319 TYPE long_varchar2_table_type IS TABLE OF VARCHAR2(4000) INDEX BY BINARY_INTEGER;
1320
1321 -- temp variables for bulk collecting properties
1322 l_prop_ids DBMS_SQL.NUMBER_TABLE;
1323 l_prop_object_ids DBMS_SQL.NUMBER_TABLE;
1324 l_prop_names DBMS_SQL.VARCHAR2_TABLE;
1325 l_datatypes DBMS_SQL.VARCHAR2_TABLE;
1326 l_canonical_values long_varchar2_table_type;
1327
1328 -- variables for traversal of the bulk collections
1329 l_curr_object_id NUMBER;
1330 l_curr_object b_object_def_type;
1331 l_curr_prop b_property_def_type;
1332 l_curr_object_props b_properties_type;
1333 l_curr_object_index NUMBER;
1334 l_curr_prop_index NUMBER;
1335
1336 BEGIN
1337 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
1338
1339 fnd_oam_debug.log(1, l_ctxt, 'Fetching compilable objects...');
1340 -- obtain all compilable objects
1341 SELECT object_id, object_type, target_type, target_id
1342 BULK COLLECT INTO l_object_ids, l_object_types, l_target_types, l_target_ids
1343 FROM fnd_oam_dscfg_objects
1344 WHERE config_instance_id = p_config_instance_id
1345 AND object_type IN (FND_OAM_DSCFG_API_PKG.G_OTYPE_DML_UPDATE_SEGMENT,
1346 FND_OAM_DSCFG_API_PKG.G_OTYPE_DML_DELETE_STMT,
1347 FND_OAM_DSCFG_API_PKG.G_OTYPE_DML_TRUNCATE_STMT,
1348 FND_OAM_DSCFG_API_PKG.G_OTYPE_PLSQL_TEXT,
1349 FND_OAM_DSCFG_API_PKG.G_OTYPE_RUN,
1350 FND_OAM_DSCFG_API_PKG.G_OTYPE_BUNDLE,
1351 FND_OAM_DSCFG_API_PKG.G_OTYPE_DOMAIN_METADATA)
1352 ORDER BY object_id DESC;
1353 fnd_oam_debug.log(1, l_ctxt, '...Done');
1354
1355 -- since we can't use l_object_ids to only get the properties we want, duplicate the object conditions above
1356 -- for selecting the entire list of properties
1357 fnd_oam_debug.log(1, l_ctxt, 'Fetching all corresponding object properties...');
1358 SELECT property_id, parent_id, property_name, datatype, canonical_value
1359 BULK COLLECT INTO l_prop_ids, l_prop_object_ids, l_prop_names, l_datatypes, l_canonical_values
1360 FROM fnd_oam_dscfg_properties
1361 WHERE parent_type = FND_OAM_DSCFG_API_PKG.G_TYPE_OBJECT
1362 AND parent_id in (SELECT object_id
1363 FROM fnd_oam_dscfg_objects
1364 WHERE config_instance_id = p_config_instance_id
1365 AND object_type IN (FND_OAM_DSCFG_API_PKG.G_OTYPE_DML_UPDATE_SEGMENT,
1366 FND_OAM_DSCFG_API_PKG.G_OTYPE_DML_DELETE_STMT,
1367 FND_OAM_DSCFG_API_PKG.G_OTYPE_DML_TRUNCATE_STMT,
1368 FND_OAM_DSCFG_API_PKG.G_OTYPE_PLSQL_TEXT,
1369 FND_OAM_DSCFG_API_PKG.G_OTYPE_RUN,
1370 FND_OAM_DSCFG_API_PKG.G_OTYPE_BUNDLE,
1371 FND_OAM_DSCFG_API_PKG.G_OTYPE_DOMAIN_METADATA))
1372 ORDER BY parent_id DESC, property_id DESC;
1373 fnd_oam_debug.log(1, l_ctxt, '...Done');
1374
1375 --now we need to go through and create b_objects entries and b_<object_type> entries.
1376 l_curr_object_index := l_object_ids.FIRST;
1377 l_curr_prop_index := l_prop_ids.FIRST;
1378 WHILE l_curr_object_index IS NOT NULL LOOP
1379 l_curr_object_id := l_object_ids(l_curr_object_index);
1380
1381 fnd_oam_debug.log(1, l_ctxt, 'Processing object_id: '||l_curr_object_id);
1382 --for each object create a new object def record
1383 l_curr_object := CREATE_OBJECT_DEF(l_curr_object_id,
1384 l_object_types(l_curr_object_index),
1385 l_target_types(l_curr_object_index),
1386 l_target_ids(l_curr_object_index));
1387
1388 --now we need to snag the properties for this object
1389 l_curr_object_props.DELETE;
1390 WHILE l_curr_prop_index IS NOT NULL LOOP
1391 --since the l_prop_object_ids is ordered, we just need to keep going until the object id isn't ours
1392 IF l_prop_object_ids(l_curr_prop_index) <> l_curr_object_id THEN
1393 EXIT;
1394 END IF;
1395
1396 fnd_oam_debug.log(1, l_ctxt, 'Processing property_id: '||l_prop_ids(l_curr_prop_index));
1397 --property belongs to this object, make a prop def and add it to the object props with the prop_id as the key
1398 l_curr_prop := CREATE_PROPERTY_DEF(l_prop_ids(l_curr_prop_index),
1399 l_prop_names(l_curr_prop_index),
1400 l_datatypes(l_curr_prop_index),
1401 l_canonical_values(l_curr_prop_index));
1402 l_curr_object_props(l_curr_prop.property_id) := l_curr_prop;
1403
1404 --move to the next prop index
1405 l_curr_prop_index := l_prop_ids.NEXT(l_curr_prop_index);
1406 END LOOP;
1407
1408 --now that we have the object and its list of properties, create an object_type-specific
1409 --cache entry
1410 CACHE_OBJECT(l_curr_object,
1411 l_curr_object_props);
1412
1413 --move on to the next object
1414 l_curr_object_index := l_object_ids.NEXT(l_curr_object_index);
1415 END LOOP;
1416
1417 --all objects fetched and cached, return success
1418 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1419 RETURN;
1420 EXCEPTION
1421 WHEN PROGRAM_ERROR THEN
1422 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1423 RAISE;
1424 WHEN OTHERS THEN
1425 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
1426 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1427 RAISE PROGRAM_ERROR;
1428 END;
1429
1430 -- Private
1431 PROCEDURE ADD_ADDITIONAL_DOMAIN_TO_GROUP(p_group_id IN NUMBER,
1432 p_additional_domain IN VARCHAR2)
1433 IS
1434 BEGIN
1435 -- uses index by table to keep out dupes
1436 b_dependency_groups(p_group_id).additional_domains(p_additional_domain) := TRUE;
1437 END;
1438
1439 -- Private
1440 -- Used to move the contents of one dependency group to another. This is done by appending the list of
1441 -- primary_domains (because those are only listed once in any given group) and inserting the list of
1442 -- additional domains into the current group. For each moved domain, we also update the domain_to_group_map.
1443 PROCEDURE REASSIGN_DEPENDENCY_GROUP(p_from_group_id IN NUMBER,
1444 p_to_group_id IN NUMBER)
1445 IS
1446 l_ctxt VARCHAR2(60) := PKG_NAME||'REASSIGN_DEPENDENCY_GROUP';
1447
1448 l_from_group b_dependency_group_def_type;
1449 --l_from_primary_domains b_domain_list_type;
1450 --l_from_additional_domains b_domain_map_type;
1451 l_domain VARCHAR2(120);
1452 l_from_index NUMBER;
1453 l_to_index NUMBER;
1454 BEGIN
1455 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
1456
1457 fnd_oam_debug.log(1, l_ctxt, 'Reassigning group '||p_from_group_id||' to '||p_to_group_id);
1458
1459 --get a local handle to the from
1460 l_from_group := b_dependency_groups(p_from_group_id);
1461
1462 --extend and copy the primary domains
1463 l_to_index := b_dependency_groups(p_to_group_id).primary_domains.COUNT + 1;
1464 b_dependency_groups(p_to_group_id).primary_domains.EXTEND(l_from_group.primary_domains.COUNT);
1465 l_from_index := l_from_group.primary_domains.FIRST;
1466 WHILE l_from_index IS NOT NULL LOOP
1467 l_domain := l_from_group.primary_domains(l_from_index);
1468 fnd_oam_debug.log(1, l_ctxt, 'Moving primary_domain: '||l_domain);
1469 b_domain_to_group_map(l_domain) := p_to_group_id;
1470 b_dependency_groups(p_to_group_id).primary_domains(l_to_index) := l_domain;
1471 l_to_index := l_to_index + 1;
1472 l_from_index := l_from_group.primary_domains.NEXT(l_from_index);
1473 END LOOP;
1474
1475 --insert the additional domains
1476 l_domain := l_from_group.additional_domains.FIRST;
1477 WHILE l_domain IS NOT NULL LOOP
1478 fnd_oam_debug.log(2, l_ctxt, 'Moving additional_domain: '||l_domain);
1479 b_domain_to_group_map(l_domain) := p_to_group_id;
1480 ADD_ADDITIONAL_DOMAIN_TO_GROUP(p_to_group_id,
1481 l_domain);
1482 l_domain := l_from_group.additional_domains.NEXT(l_domain);
1483 END LOOP;
1484
1485 --remove the from group
1486 fnd_oam_debug.log(1, l_ctxt, 'Removing the from group.');
1487 b_dependency_groups.DELETE(p_from_group_id);
1488
1489 --success
1490 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1491 EXCEPTION
1492 WHEN OTHERS THEN
1493 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
1494 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1495 RAISE PROGRAM_ERROR;
1496 END;
1497
1498 -- Private
1499 PROCEDURE COMPUTE_DEPENDENCY_GROUPS
1500 IS
1501 l_ctxt VARCHAR2(60) := PKG_NAME||'COMPUTE_DEPENDENCY_GROUPS';
1502
1503 l_primary_domain VARCHAR2(120);
1504 l_additional_domain VARCHAR2(120);
1505 l_additional_domains b_domain_list_type;
1506 l_object_id NUMBER;
1507 l_object_ids b_number_list_type;
1508
1509 l_next_group_id NUMBER := 1;
1510 l_this_group_id NUMBER;
1511 l_found_group_id NUMBER;
1512
1513 k NUMBER;
1514 j NUMBER;
1515 BEGIN
1516 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
1517
1518 --traverse the map of primary domains, ignore the NULL domain key, shouldn't be allowed.
1519 l_primary_domain := b_primary_domains.FIRST;
1520 WHILE l_primary_domain IS NOT NULL LOOP
1521 --default objects in this primary domain to the next available group_id and store
1522 --the bidirectional mapping between them. All future conflicting domains will be rolled into this
1523 --one.
1524 fnd_oam_debug.log(1, l_ctxt, 'Processing primary_domain: '||l_primary_domain);
1525 l_this_group_id := l_next_group_id;
1526 fnd_oam_debug.log(1, l_ctxt, 'Given group ID: '||l_this_group_id);
1527 l_next_group_id := l_next_group_id + 1;
1528 b_domain_to_group_map(l_primary_domain) := l_this_group_id;
1529 b_dependency_groups(l_this_group_id) := CREATE_DEPENDENCY_GROUP_DEF(l_primary_domain);
1530
1531 --get the objects in this primary domain and loop over them to look for additional domains
1532 --that may conflict with existing dependency groups.
1533 l_object_ids := b_primary_domains(l_primary_domain);
1534 k := l_object_ids.FIRST;
1535 WHILE k IS NOT NULL LOOP
1536 l_object_id := l_object_ids(k);
1537 fnd_oam_debug.log(1, l_ctxt, 'Processing domain object_id: '||l_object_id);
1538 -- see if the object_id has any additional domains, if it doesn't then this object produces no conflicts.
1539 IF b_objects(l_object_id).additional_domains IS NOT NULL THEN
1540 fnd_oam_debug.log(1, l_ctxt, 'Has Additional Domains');
1541 --loop over the additional domains
1542 l_additional_domains := b_objects(l_object_id).additional_domains;
1543 j := l_additional_domains.FIRST;
1544 WHILE j IS NOT NULL LOOP
1545 l_additional_domain := l_additional_domains(j);
1546 fnd_oam_debug.log(1, l_ctxt, 'Processing additional_domain: '||l_additional_domain);
1547 --see if the additional domain has already been seen
1548 IF b_domain_to_group_map.EXISTS(l_additional_domain) THEN
1549 --see if the additional domain is not already in this group, if it is we don't have to do anything
1550 l_found_group_id := b_domain_to_group_map(l_additional_domain);
1551 IF l_found_group_id <> l_this_group_id THEN
1552 --migrate the contents of the found group to the current,"this" group
1553 REASSIGN_DEPENDENCY_GROUP(p_from_group_id => l_found_group_id,
1554 p_to_group_id => l_this_group_id);
1555 END IF;
1556 ELSE
1557 --hasn't been seen before, just add the domain_to_group mapping
1558 b_domain_to_group_map(l_additional_domain) := l_this_group_id;
1559 END IF;
1560
1561 --always add this additional domain to the current group in case the re-assign took somebody else's
1562 --primary.
1563 ADD_ADDITIONAL_DOMAIN_TO_GROUP(l_this_group_id,
1564 l_additional_domain);
1565
1566 j := l_additional_domains.NEXT(j);
1567 END LOOP;
1568 END IF;
1569 k := l_object_ids.NEXT(k);
1570 END LOOP;
1571
1572 l_primary_domain := b_primary_domains.NEXT(l_primary_domain);
1573 END LOOP;
1574
1575 -- success
1576 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1577 RETURN;
1578 EXCEPTION
1579 WHEN PROGRAM_ERROR THEN
1580 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1581 RAISE;
1582 WHEN OTHERS THEN
1583 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
1584 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1585 RAISE PROGRAM_ERROR;
1586 END;
1587
1588 -- Private, helper to COMPILE_CONFIG_INSTANCE to dump out the run entity
1589 PROCEDURE GENERATE_ENGINE_RUN(p_config_instance_id IN NUMBER)
1590 IS
1591 PRAGMA AUTONOMOUS_TRANSACTION;
1592
1593 l_ctxt VARCHAR2(60) := PKG_NAME||'GENERATE_ENGINE_RUN';
1594
1595 l_dbname VARCHAR2(30);
1596 l_property_id NUMBER;
1597 l_msg VARCHAR2(4000);
1598
1599 l_display_name VARCHAR2(120);
1600 l_description VARCHAR2(2000);
1601 l_language VARCHAR2(12);
1602 BEGIN
1603 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
1604
1605 --see if we need to create a run object if none was cached on fetch
1606 IF b_run.object_id IS NULL THEN
1607 fnd_oam_debug.log(2, l_ctxt, 'Creating new run object');
1608 FND_OAM_DSCFG_API_PKG.ADD_OBJECT(p_object_type => FND_OAM_DSCFG_API_PKG.G_OTYPE_RUN,
1609 x_object_id => b_run.object_id);
1610 fnd_oam_debug.log(2, l_ctxt, 'run object_id: '||b_run.object_id);
1611 --add an entry to the b_objects array so we can cache messages there
1612 b_objects(b_run.object_id) := CREATE_OBJECT_DEF(b_run.object_id,
1613 FND_OAM_DSCFG_API_PKG.G_OTYPE_RUN);
1614 END IF;
1615
1616 --validate the run mode
1617 IF b_run.run_mode IS NULL THEN
1618 b_run.run_mode := B_DEFAULT_RUN_MODE;
1619 FND_OAM_DSCFG_API_PKG.ADD_OBJECT_PROPERTY(p_object_id => b_run.object_id,
1620 p_property_name => FND_OAM_DSCFG_API_PKG.G_PROP_RUN_MODE,
1621 p_varchar2_value => b_run.run_mode,
1622 x_property_id => l_property_id);
1623 ELSE
1624 IF b_run.run_mode NOT IN (FND_OAM_DSCRAM_UTILS_PKG.G_MODE_NORMAL,
1625 FND_OAM_DSCRAM_UTILS_PKG.G_MODE_TEST,
1626 FND_OAM_DSCRAM_UTILS_PKG.G_MODE_TEST_NO_EXEC,
1627 FND_OAM_DSCRAM_UTILS_PKG.G_MODE_DIAGNOSTIC) THEN
1628 l_msg := 'Invalid run mode specified: "'||b_run.run_mode||'".';
1629 fnd_oam_debug.log(3, l_ctxt, l_msg);
1630 MARK_OBJECT_AS_ERRORED(b_run.object_id,
1631 l_msg);
1632 RAISE PROGRAM_ERROR;
1633 END IF;
1634 END IF;
1635 fnd_oam_debug.log(1, l_ctxt, 'Run Mode: '||b_run.run_mode);
1636
1637 --default the valid_check_interval if not present
1638 IF b_run.valid_check_interval IS NULL THEN
1639 b_run.valid_check_interval := GET_DFLT_VALID_CHECK_INTERVAL;
1640 FND_OAM_DSCFG_API_PKG.ADD_OBJECT_PROPERTY(p_object_id => b_run.object_id,
1641 p_property_name => FND_OAM_DSCFG_API_PKG.G_PROP_VALID_CHECK_INTERVAL,
1642 p_number_value => b_run.valid_check_interval,
1643 x_property_id => l_property_id);
1644 ELSE
1645 IF b_run.valid_check_interval < 0 THEN
1646 l_msg := 'Invalid valid_check_interval specified: "'||b_run.valid_check_interval||'".';
1647 fnd_oam_debug.log(3, l_ctxt, l_msg);
1648 MARK_OBJECT_AS_ERRORED(b_run.object_id,
1649 l_msg);
1650 RAISE PROGRAM_ERROR;
1651 END IF;
1652 END IF;
1653 fnd_oam_debug.log(1, l_ctxt, 'Valid Check Interval: '||b_run.valid_check_interval);
1654
1655 --default the # of bundles using what we've read into b_bundles or the default
1656 IF b_run.num_bundles IS NULL THEN
1657 IF b_bundles.COUNT > 0 THEN
1658 b_run.num_bundles := b_bundles.COUNT;
1659 --defer the check if this is greater than the # of hosts in the instance until GENERATE_BUNDLES
1660 ELSE
1661 b_run.num_bundles := B_DEFAULT_NUM_BUNDLES;
1662 END IF;
1663 FND_OAM_DSCFG_API_PKG.ADD_OBJECT_PROPERTY(p_object_id => b_run.object_id,
1664 p_property_name => FND_OAM_DSCFG_API_PKG.G_PROP_NUM_BUNDLES,
1665 p_number_value => b_run.num_bundles,
1666 x_property_id => l_property_id);
1667 ELSE
1668 IF b_run.num_bundles < 1 THEN
1669 l_msg := 'Invalid num_bundles specified: "'||b_run.num_bundles||'".';
1670 fnd_oam_debug.log(3, l_ctxt, l_msg);
1671 MARK_OBJECT_AS_ERRORED(b_run.object_id,
1672 l_msg);
1673 RAISE PROGRAM_ERROR;
1674 END IF;
1675 END IF;
1676 fnd_oam_debug.log(1, l_ctxt, 'Number of Bundles: '||b_run.num_bundles);
1677
1678 --make sure the num_bundles is >= the # of bundle objects we read in
1679 IF b_bundles.COUNT > b_run.num_bundles THEN
1680 l_msg := 'Number of specified run bundles, '||b_run.num_bundles||', less than the number of bundles seen in configuration, '||b_bundles.COUNT;
1681 fnd_oam_debug.log(3, l_ctxt, l_msg);
1682 MARK_OBJECT_AS_ERRORED(b_run.object_id,
1683 l_msg);
1684 RAISE PROGRAM_ERROR;
1685 END IF;
1686
1687 --now we need to prep the actual engine entity
1688 IF b_run.run_id IS NULL THEN
1689 --get a run_id
1690 SELECT FND_OAM_DSCRAM_RUNS_S.NEXTVAL
1691 INTO b_run.run_id
1692 FROM dual;
1693 ELSE
1694 fnd_oam_debug.log(1, l_ctxt, 'Deleting Existing, Stale run_id: '||b_run.run_id);
1695 --TODO: make this smarter
1696 IF NOT FND_OAM_DSCRAM_UTILS_PKG.DELETE_RUN(b_run.run_id) THEN
1697 l_msg := 'Failed to delete previously compiled run: '||b_run.run_id;
1698 fnd_oam_debug.log(3, l_ctxt, l_msg);
1699 END IF;
1700 END IF;
1701
1702 --query the current db as the target_dbname
1703 SELECT UPPER(name)
1704 INTO l_dbname
1705 FROM v$database
1706 WHERE rownum < 2;
1707
1708 --at this point insert a new run, we'll update the weight later
1709 INSERT INTO FND_OAM_DSCRAM_RUNS_B (RUN_ID,
1710 RUN_STATUS,
1711 RUN_MODE,
1712 TARGET_DBNAME,
1713 CONFIG_INSTANCE_ID,
1714 VALID_CHECK_INTERVAL,
1715 CREATED_BY,
1716 CREATION_DATE,
1717 LAST_UPDATED_BY,
1718 LAST_UPDATE_DATE,
1719 LAST_UPDATE_LOGIN
1720 )
1721 VALUES
1722 (b_run.run_id,
1723 FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_UNPROCESSED,
1724 b_run.run_mode,
1725 l_dbname,
1726 p_config_instance_id,
1727 b_run.valid_check_interval,
1728 FND_GLOBAL.USER_ID,
1729 SYSDATE,
1730 FND_GLOBAL.USER_ID,
1731 SYSDATE,
1732 FND_GLOBAL.USER_ID)
1733 RETURNING run_id INTO b_run.run_id;
1734 fnd_oam_debug.log(1, l_ctxt, 'Created new run_id: '||b_run.run_id);
1735
1736 --store the run_id
1737 FND_OAM_DSCFG_API_PKG.SET_OR_ADD_OBJECT_PROPERTY(p_object_id => b_run.object_id,
1738 p_property_name => FND_OAM_DSCFG_API_PKG.G_PROP_RUN_ID,
1739 p_number_value => b_run.run_id,
1740 x_property_id => l_property_id);
1741
1742 fnd_oam_debug.log(1, l_ctxt, 'Querying config_instance attributes');
1743 -- get the name/description from the config instance
1744 SELECT name, description, language
1745 INTO l_display_name, l_description, l_language
1746 FROM fnd_oam_dscfg_instances
1747 WHERE config_instance_id = p_config_instance_id;
1748
1749 fnd_oam_debug.log(1, l_ctxt, 'Inserting runs_tl row');
1750 INSERT INTO FND_OAM_DSCRAM_RUNS_TL (RUN_ID,
1751 DISPLAY_NAME,
1752 DESCRIPTION,
1753 LANGUAGE,
1754 SOURCE_LANG,
1755 CREATED_BY,
1756 CREATION_DATE,
1757 LAST_UPDATED_BY,
1758 LAST_UPDATE_DATE,
1759 LAST_UPDATE_LOGIN
1760 )
1761 VALUES
1762 (b_run.run_id,
1763 l_display_name||'('||b_run.run_id||')',
1764 l_description,
1765 l_language,
1766 l_language,
1767 --FND_GLOBAL.CURRENT_LANGUAGE,
1768 FND_GLOBAL.USER_ID,
1769 SYSDATE,
1770 FND_GLOBAL.USER_ID,
1771 SYSDATE,
1772 FND_GLOBAL.USER_ID);
1773
1774 COMMIT;
1775
1776 --success
1777 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1778 EXCEPTION
1779 WHEN PROGRAM_ERROR THEN
1780 ROLLBACK;
1781 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1782 RAISE;
1783 WHEN OTHERS THEN
1784 ROLLBACK;
1785 --try to mark the run object
1786 IF b_run.object_id IS NOT NULL THEN
1787 MARK_OBJECT_AS_ERRORED(b_run.object_id,
1788 l_ctxt,
1789 SQLCODE,
1790 SQLERRM);
1791 END IF;
1792 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
1793 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
1794 RAISE PROGRAM_ERROR;
1795 END;
1796
1797 -- Private, helper to COMPILE_CONFIG_INSTANCE to dump out bundle entities
1798 PROCEDURE GENERATE_ENGINE_BUNDLES
1799 IS
1800 PRAGMA AUTONOMOUS_TRANSACTION;
1801
1802 l_ctxt VARCHAR2(60) := PKG_NAME||'GENERATE_ENGINE_BUNDLES';
1803
1804
1805 l_host_names DBMS_SQL.VARCHAR2_TABLE;
1806 l_host_name VARCHAR2(256);
1807 l_bundle_object_id NUMBER;
1808 l_property_id NUMBER;
1809
1810 k NUMBER;
1811 j NUMBER;
1812 l_msg VARCHAR2(4000);
1813 l_found BOOLEAN;
1814 l_bundles_to_create NUMBER;
1815
1816 BEGIN
1817 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
1818
1819 --get the list of hosts for this DB
1820 SELECT UPPER(host_name)
1821 BULK COLLECT INTO l_host_names
1822 FROM gv$instance;
1823
1824 --make sure we don't have more bundles than hosts
1825 IF b_run.num_bundles > l_host_names.COUNT THEN
1826 l_msg := 'More bundles defined in run configuration, '||b_run.num_bundles||', than defined for database: '||l_host_names.COUNT;
1827 fnd_oam_debug.log(3, l_ctxt, l_msg);
1828 MARK_OBJECT_AS_ERRORED(b_run.object_id,
1829 l_msg);
1830 RAISE PROGRAM_ERROR;
1831 END IF;
1832
1833 --make sure each bundle with a hostname has a valid, different hostname. Also check and default the
1834 --workers_allowed, batch_size and min_parallel_weight attributes
1835 k := b_bundles.FIRST;
1836 WHILE k IS NOT NULL LOOP
1837 l_host_name := b_bundles(k).target_hostname;
1838 fnd_oam_debug.log(1, l_ctxt, 'Validating Bundle with object_id: '||k);
1839
1840 --if a host is specified, do validation/bookkeeping
1841 IF l_host_name IS NOT NULL THEN
1842 fnd_oam_debug.log('Validating specified host_name: '||l_host_name);
1843 --see if the host name is already used
1844 IF b_host_name_map.EXISTS(l_host_name) THEN
1845 l_msg := 'Target Hostname "'||l_host_name||'" already used by object id: '||b_host_name_map(l_host_name);
1846 fnd_oam_debug.log(3, l_ctxt, l_msg);
1847 MARK_OBJECT_AS_ERRORED(k,
1848 l_msg);
1849 RAISE PROGRAM_ERROR;
1850 ELSE
1851 --hostname not seen yet, remove it from l_host_names
1852 l_found := FALSE;
1853 j := l_host_names.FIRST;
1854 WHILE j IS NOT NULL LOOP
1855 IF l_host_names(j) = l_host_name THEN
1856 l_host_names.DELETE(j);
1857 l_found := TRUE;
1858 EXIT;
1859 END IF;
1860 j := l_host_names.NEXT(j);
1861 END LOOP;
1862
1863 --if we didn't find it, it's invalid
1864 IF NOT l_found THEN
1865 l_msg := 'Target Hostname "'||l_host_name||'" is not a hostname attached to this instance, check gv$instance.host_name.';
1866 fnd_oam_debug.log(3, l_ctxt, l_msg);
1867 MARK_OBJECT_AS_ERRORED(k,
1868 l_msg);
1869 RAISE PROGRAM_ERROR;
1870 END IF;
1871
1872 --add it to the used host names map
1873 b_host_name_map(l_host_name) := k;
1874 END IF;
1875 END IF;
1876
1877 --validate the workers_allowed
1878 IF b_bundles(k).workers_allowed IS NULL THEN
1879 b_bundles(k).workers_allowed := GET_DEFAULT_NUM_WORKERS;
1880 FND_OAM_DSCFG_API_PKG.ADD_OBJECT_PROPERTY(p_object_id => k,
1881 p_property_name => FND_OAM_DSCFG_API_PKG.G_PROP_WORKERS_ALLOWED,
1882 p_number_value => b_bundles(k).workers_allowed,
1883 x_property_id => l_property_id);
1884 ELSE
1885 IF b_bundles(k).workers_allowed < 1 THEN
1886 l_msg := 'Invalid workers_allowed specified: "'||b_bundles(k).workers_allowed||'".';
1887 fnd_oam_debug.log(3, l_ctxt, l_msg);
1888 MARK_OBJECT_AS_ERRORED(k,
1889 l_msg);
1890 RAISE PROGRAM_ERROR;
1891 END IF;
1892 END IF;
1893 fnd_oam_debug.log(1, l_ctxt, 'Workers Allowed: '||b_bundles(k).workers_allowed);
1894
1895 --validate the batch_size
1896 IF b_bundles(k).batch_size IS NULL THEN
1897 b_bundles(k).batch_size := GET_DEFAULT_BATCH_SIZE;
1898 FND_OAM_DSCFG_API_PKG.ADD_OBJECT_PROPERTY(p_object_id => k,
1899 p_property_name => FND_OAM_DSCFG_API_PKG.G_PROP_BATCH_SIZE,
1900 p_number_value => b_bundles(k).batch_size,
1901 x_property_id => l_property_id);
1902 ELSE
1903 IF b_bundles(k).batch_size < 1 THEN
1904 l_msg := 'Invalid batch_size specified: "'||b_bundles(k).batch_size||'".';
1905 fnd_oam_debug.log(3, l_ctxt, l_msg);
1906 MARK_OBJECT_AS_ERRORED(k,
1907 l_msg);
1908 RAISE PROGRAM_ERROR;
1909 END IF;
1910 END IF;
1911 fnd_oam_debug.log(1, l_ctxt, 'Batch Size: '||b_bundles(k).batch_size);
1912
1913 --validate the min_parallel_unit_weight
1914 IF b_bundles(k).min_parallel_unit_weight IS NULL THEN
1915 b_bundles(k).min_parallel_unit_weight := GET_DFLT_MIN_PARALLEL_WEIGHT;
1916 FND_OAM_DSCFG_API_PKG.ADD_OBJECT_PROPERTY(p_object_id => k,
1917 p_property_name => FND_OAM_DSCFG_API_PKG.G_PROP_MIN_PARALLEL_WEIGHT,
1918 p_number_value => b_bundles(k).min_parallel_unit_weight,
1919 x_property_id => l_property_id);
1920 ELSE
1921 IF b_bundles(k).min_parallel_unit_weight < 1 THEN
1922 l_msg := 'Invalid min_parallel_unit_weight specified: "'||b_bundles(k).min_parallel_unit_weight||'".';
1923 fnd_oam_debug.log(3, l_ctxt, l_msg);
1924 MARK_OBJECT_AS_ERRORED(k,
1925 l_msg);
1926 RAISE PROGRAM_ERROR;
1927 END IF;
1928 END IF;
1929 fnd_oam_debug.log(1, l_ctxt, 'Minimum unit weight to parallelize: '||b_bundles(k).min_parallel_unit_weight);
1930
1931 k := b_bundles.NEXT(k);
1932 END LOOP;
1933
1934 --if there's more than one bundle, loop through the bundles and give each one without a hostname one from l_host_names
1935 IF b_bundles.COUNT > 1 THEN
1936 k := b_bundles.FIRST;
1937 WHILE k IS NOT NULL LOOP
1938 l_host_name := b_bundles(k).target_hostname;
1939
1940 IF l_host_name IS NULL THEN
1941 --just get the next one off of l_host_names
1942 b_bundles(k).target_hostname := l_host_names(l_host_names.FIRST);
1943 fnd_oam_debug.log(1, l_ctxt, 'Assigned host_name "'||l_host_name||'" to bundle_object_id: '||k);
1944 l_host_names.DELETE(l_host_names.FIRST);
1945 b_host_name_map(b_bundles(k).target_hostname) := k;
1946
1947 FND_OAM_DSCFG_API_PKG.ADD_OBJECT_PROPERTY(p_object_id => k,
1948 p_property_name => FND_OAM_DSCFG_API_PKG.G_PROP_TARGET_HOSTNAME,
1949 p_varchar2_value => b_bundles(k).target_hostname,
1950 x_property_id => l_property_id);
1951 END IF;
1952
1953 k := b_bundles.NEXT(k);
1954 END LOOP;
1955 END IF;
1956
1957 --make sure we've got as many b_bundles entries as expected by b_run.num_bundles.
1958 --As an invariant, we can't have more but if we have less we need to create some default bundles.
1959 IF b_bundles.COUNT < b_run.num_bundles THEN
1960 l_bundles_to_create := b_run.num_bundles - b_bundles.COUNT;
1961 fnd_oam_debug.log(1, l_ctxt, 'Creating '||l_bundles_to_create||' bundle objects...');
1962 FOR k in 1..l_bundles_to_create LOOP
1963 --create a bundle object
1964 FND_OAM_DSCFG_API_PKG.ADD_OBJECT(p_object_type => FND_OAM_DSCFG_API_PKG.G_OTYPE_BUNDLE,
1965 x_object_id => l_bundle_object_id);
1966 fnd_oam_debug.log(1, l_ctxt, 'Bundle object_id: '||l_bundle_object_id);
1967 b_objects(l_bundle_object_id) := CREATE_OBJECT_DEF(l_bundle_object_id,
1968 FND_OAM_DSCFG_API_PKG.G_OTYPE_BUNDLE);
1969
1970 --use the next available host name
1971 b_bundles(l_bundle_object_id) := CREATE_BUNDLE_DEF(l_host_names(l_host_names.FIRST));
1972 l_host_names.DELETE(l_host_names.FIRST);
1973 b_host_name_map(b_bundles(l_bundle_object_id).target_hostname) := l_bundle_object_id;
1974
1975 --add properties for mandatory attributes
1976 FND_OAM_DSCFG_API_PKG.ADD_OBJECT_PROPERTY(p_object_id => l_bundle_object_id,
1977 p_property_name => FND_OAM_DSCFG_API_PKG.G_PROP_TARGET_HOSTNAME,
1978 p_varchar2_value => b_bundles(l_bundle_object_id).target_hostname,
1979 x_property_id => l_property_id);
1980 fnd_oam_debug.log(1, l_ctxt, 'Target Hostname: '||b_bundles(l_bundle_object_id).target_hostname);
1981 FND_OAM_DSCFG_API_PKG.ADD_OBJECT_PROPERTY(p_object_id => l_bundle_object_id,
1982 p_property_name => FND_OAM_DSCFG_API_PKG.G_PROP_WORKERS_ALLOWED,
1983 p_number_value => b_bundles(l_bundle_object_id).workers_allowed,
1984 x_property_id => l_property_id);
1985 fnd_oam_debug.log(1, l_ctxt, 'Workers Allowed: '||b_bundles(l_bundle_object_id).workers_allowed);
1986 FND_OAM_DSCFG_API_PKG.ADD_OBJECT_PROPERTY(p_object_id => l_bundle_object_id,
1987 p_property_name => FND_OAM_DSCFG_API_PKG.G_PROP_BATCH_SIZE,
1988 p_number_value => b_bundles(l_bundle_object_id).batch_size,
1989 x_property_id => l_property_id);
1990 fnd_oam_debug.log(1, l_ctxt, 'Batch Size: '||b_bundles(l_bundle_object_id).batch_size);
1991 FND_OAM_DSCFG_API_PKG.ADD_OBJECT_PROPERTY(p_object_id => l_bundle_object_id,
1992 p_property_name => FND_OAM_DSCFG_API_PKG.G_PROP_MIN_PARALLEL_WEIGHT,
1993 p_number_value => b_bundles(l_bundle_object_id).min_parallel_unit_weight,
1994 x_property_id => l_property_id);
1995 fnd_oam_debug.log(1, l_ctxt, 'Min Parallel Unit Weight: '||b_bundles(l_bundle_object_id).min_parallel_unit_weight);
1996 END LOOP;
1997 END IF;
1998
1999 --At this point, we should have b_run.num_bundles entries in b_bundles and each should be valid, create entries for each.
2000 --TODO: when we make the run smarter so existing runs are partially re-compiled, this section will need to be
2001 --addressed to use the bundle_id. For now, just overwrite it.
2002 k := b_bundles.FIRST;
2003 WHILE k IS NOT NULL LOOP
2004 --do the insert, update weight later
2005 INSERT INTO FND_OAM_DSCRAM_BUNDLES (BUNDLE_ID,
2006 RUN_ID,
2007 BUNDLE_STATUS,
2008 TARGET_HOSTNAME,
2009 WORKERS_ALLOWED,
2010 WORKERS_ASSIGNED,
2011 BATCH_SIZE,
2012 MIN_PARALLEL_UNIT_WEIGHT,
2013 CREATED_BY,
2014 CREATION_DATE,
2015 LAST_UPDATED_BY,
2016 LAST_UPDATE_DATE,
2017 LAST_UPDATE_LOGIN
2018 )
2019 VALUES
2020 (FND_OAM_DSCRAM_BUNDLES_S.NEXTVAL,
2021 b_run.run_id,
2022 FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_UNPROCESSED,
2023 b_bundles(k).target_hostname,
2024 b_bundles(k).workers_allowed,
2025 0,
2026 b_bundles(k).batch_size,
2027 b_bundles(k).min_parallel_unit_weight,
2028 FND_GLOBAL.USER_ID,
2029 SYSDATE,
2030 FND_GLOBAL.USER_ID,
2031 SYSDATE,
2032 FND_GLOBAL.USER_ID)
2033 RETURNING bundle_id INTO b_bundles(k).bundle_id;
2034 fnd_oam_debug.log(1, l_ctxt, 'Bundle Object ID ('||k||') created bundle_id ('||b_bundles(k).bundle_id||')');
2035
2036 --add the property for bundle id
2037 FND_OAM_DSCFG_API_PKG.SET_OR_ADD_OBJECT_PROPERTY(p_object_id => k,
2038 p_property_name => FND_OAM_DSCFG_API_PKG.G_PROP_BUNDLE_ID,
2039 p_number_value => b_bundles(k).bundle_id,
2040 x_property_id => l_property_id);
2041
2042 k := b_bundles.NEXT(k);
2043 END LOOP;
2044
2045 COMMIT;
2046
2047 --success
2048 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2049 EXCEPTION
2050 WHEN PROGRAM_ERROR THEN
2051 ROLLBACK;
2052 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2053 RAISE;
2054 WHEN OTHERS THEN
2055 ROLLBACK;
2056 --mark the run object
2057 MARK_OBJECT_AS_ERRORED(b_run.object_id,
2058 l_ctxt,
2059 SQLCODE,
2060 SQLERRM);
2061 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
2062 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2063 RAISE PROGRAM_ERROR;
2064 END;
2065
2066 -- Private, gets the table_objects_def entity from the px_table_bound_map or creates one if necessary.
2067 FUNCTION GET_TABLE_OBJECTS_DEF(px_table_bound_map IN OUT NOCOPY b_table_bound_map_type,
2068 p_table_owner IN VARCHAR2,
2069 p_table_name IN VARCHAR2)
2070 RETURN b_table_objects_def_type
2071 IS
2072 l_ctxt VARCHAR2(60) := PKG_NAME||'GET_TABLE_OBJECTS_DEF';
2073
2074 l_table_name_map b_table_name_map_type;
2075 l_table_objects_def b_table_objects_def_type; --allocate a new one using it's create each time
2076 BEGIN
2077 --see if the table_bound_map has this table_owner
2078 IF px_table_bound_map.EXISTS(p_table_owner) THEN
2079 IF px_table_bound_map(p_table_owner).EXISTS(p_table_name) THEN
2080 RETURN px_table_bound_map(p_table_owner)(p_table_name);
2081 ELSE
2082 --has owner, but no table_name entry
2083 l_table_objects_def := CREATE_TABLE_OBJECTS_DEF;
2084 px_table_bound_map(p_table_owner)(p_table_name) := l_table_objects_def;
2085 RETURN l_table_objects_def;
2086 END IF;
2087 ELSE
2088 --owner isn't present so add the table name to the name_map with a new table_objects_def
2089 l_table_objects_def := CREATE_TABLE_OBJECTS_DEF;
2090 l_table_name_map(p_table_name) := l_table_objects_def;
2091 px_table_bound_map(p_table_owner) := l_table_name_map;
2092 RETURN l_table_objects_def;
2093 END IF;
2094 EXCEPTION
2095 WHEN OTHERS THEN
2096 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
2097 RAISE;
2098 END;
2099
2100 -- Private, helper to ADD_ENGINE_UNITS to do the physical insert
2101 PROCEDURE ADD_ENGINE_UNIT(p_task_id IN NUMBER,
2102 p_unit_type IN VARCHAR2,
2103 p_concurrent_group_unit_id IN NUMBER DEFAULT NULL,
2104 p_phase IN NUMBER DEFAULT NULL,
2105 p_priority IN NUMBER DEFAULT NULL,
2106 p_weight IN NUMBER DEFAULT NULL,
2107 p_workers_allowed IN NUMBER DEFAULT NULL,
2108 p_unit_object_owner IN VARCHAR2 DEFAULT NULL,
2109 p_unit_object_name IN VARCHAR2 DEFAULT NULL,
2110 p_batch_size IN VARCHAR2 DEFAULT NULL,
2111 p_error_fatality_level IN VARCHAR2 DEFAULT NULL,
2112 p_disable_splitting IN VARCHAR2 DEFAULT NULL,
2113 px_unit_id IN OUT NOCOPY NUMBER)
2114 IS
2115 l_ctxt VARCHAR2(60) := PKG_NAME||'ADD_UNIT';
2116
2117 l_unit_id NUMBER;
2118 BEGIN
2119 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
2120
2121 IF px_unit_id IS NULL THEN
2122 SELECT FND_OAM_DSCRAM_UNITS_S.NEXTVAL
2123 INTO px_unit_id
2124 FROM dual;
2125 END IF;
2126
2127 INSERT INTO FND_OAM_DSCRAM_UNITS (UNIT_ID,
2128 TASK_ID,
2129 CONCURRENT_GROUP_UNIT_ID,
2130 UNIT_TYPE,
2131 UNIT_STATUS,
2132 PHASE,
2133 PRIORITY,
2134 WEIGHT,
2135 SUGGEST_WORKERS_ALLOWED,
2136 WORKERS_ASSIGNED,
2137 UNIT_OBJECT_OWNER,
2138 UNIT_OBJECT_NAME,
2139 BATCH_SIZE,
2140 ERROR_FATALITY_LEVEL,
2141 SUGGEST_DISABLE_SPLITTING,
2142 CREATED_BY,
2143 CREATION_DATE,
2144 LAST_UPDATED_BY,
2145 LAST_UPDATE_DATE,
2146 LAST_UPDATE_LOGIN
2147 )
2148 VALUES
2149 (px_unit_id,
2150 p_task_id,
2151 p_concurrent_group_unit_id,
2152 p_unit_type,
2153 FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_UNPROCESSED,
2154 p_phase,
2155 p_priority,
2156 p_weight,
2157 p_workers_allowed,
2158 0,
2159 p_unit_object_owner,
2160 p_unit_object_name,
2161 p_batch_size,
2162 p_error_fatality_level,
2163 p_disable_splitting,
2164 FND_GLOBAL.USER_ID,
2165 SYSDATE,
2166 FND_GLOBAL.USER_ID,
2167 SYSDATE,
2168 FND_GLOBAL.USER_ID)
2169 RETURNING UNIT_ID INTO l_unit_id;
2170
2171 px_unit_id := l_unit_id;
2172
2173 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2174 EXCEPTION
2175 WHEN OTHERS THEN
2176 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
2177 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2178 RAISE;
2179 END;
2180
2181 --Simple helper to get the next unit id from its sequence.
2182 FUNCTION GET_NEXT_UNIT_ID
2183 RETURN NUMBER
2184 IS
2185 l_retval NUMBER;
2186 BEGIN
2187 SELECT FND_OAM_DSCRAM_UNITS_S.NEXTVAL
2188 INTO l_retval
2189 FROM DUAL;
2190 RETURN l_retval;
2191 END;
2192
2193 -- Helper to ADD_ENGINE_UNITS to update the logical and physical weight counters.
2194 PROCEDURE INTEGRATE_WEIGHTS(px_parent_logical_weight IN OUT NOCOPY NUMBER,
2195 px_parent_physical_weight IN OUT NOCOPY NUMBER,
2196 p_child_logical_weight IN NUMBER,
2197 p_child_physical_weight IN NUMBER)
2198 IS
2199 BEGIN
2200 IF px_parent_logical_weight IS NOT NULL THEN
2201 IF p_child_logical_weight IS NULL THEN
2202 px_parent_logical_weight := NULL;
2203 ELSE
2204 px_parent_logical_weight := px_parent_logical_weight + p_child_logical_weight;
2205 END IF;
2206 END IF;
2207 px_parent_physical_weight := px_parent_physical_weight + NVL(p_child_physical_weight, 0);
2208 END;
2209
2210 -- create a dml entry for a given unit
2211 PROCEDURE ADD_ENGINE_DML(p_unit_id IN NUMBER,
2212 p_stmt IN VARCHAR2,
2213 p_where_clause IN VARCHAR2 DEFAULT NULL,
2214 p_priority IN NUMBER DEFAULT NULL,
2215 p_weight IN NUMBER DEFAULT NULL,
2216 x_dml_id OUT NOCOPY NUMBER)
2217 IS
2218 l_ctxt VARCHAR2(60) := PKG_NAME||'ADD_ENGINE_DML';
2219 l_dml_id NUMBER;
2220 BEGIN
2221 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
2222
2223 INSERT INTO FND_OAM_DSCRAM_DMLS (DML_ID,
2224 UNIT_ID,
2225 PRIORITY,
2226 WEIGHT,
2227 DML_STMT,
2228 DML_WHERE_CLAUSE,
2229 CREATED_BY,
2230 CREATION_DATE,
2231 LAST_UPDATED_BY,
2232 LAST_UPDATE_DATE,
2233 LAST_UPDATE_LOGIN
2234 )
2235 VALUES
2236 (FND_OAM_DSCRAM_DMLS_S.NEXTVAL,
2237 p_unit_id,
2238 p_priority,
2239 p_weight,
2240 p_stmt,
2241 p_where_clause,
2242 FND_GLOBAL.USER_ID,
2243 SYSDATE,
2244 FND_GLOBAL.USER_ID,
2245 SYSDATE,
2246 FND_GLOBAL.USER_ID)
2247 RETURNING DML_ID INTO l_dml_id;
2248
2249 x_dml_id := l_dml_id;
2250
2251 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2252 EXCEPTION
2253 WHEN OTHERS THEN
2254 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Exception: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
2255 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2256 RAISE;
2257 END;
2258
2259 -- Helper to construct a DML DELETE statement and add it to a unit.
2260 FUNCTION ADD_ENGINE_DELETE_DML(p_unit_id IN NUMBER,
2261 p_object_id IN NUMBER,
2262 x_weight OUT NOCOPY NUMBER)
2263 RETURN BOOLEAN
2264 IS
2265 l_ctxt VARCHAR2(60) := PKG_NAME||'ADD_ENGINE_DELETE_DML';
2266
2267 l_delete_def b_dml_delete_stmt_def_type;
2268 l_stmt VARCHAR2(4000);
2269 l_weight NUMBER;
2270 l_dml_id NUMBER;
2271 BEGIN
2272 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
2273
2274 --get a reference
2275 l_delete_def := b_dml_delete_stmts(p_object_id);
2276
2277 --construct the delete stmt
2278 l_stmt := 'DELETE FROM '||l_delete_def.table_owner||'.'||l_delete_def.table_name;
2279
2280 --compute the weight
2281 l_weight := CEIL(NVL(l_delete_def.weight, B_DELETE_WEIGHT_MODIFIER *
2282 FND_OAM_DSCFG_UTILS_PKG.GET_TABLE_WEIGHT(l_delete_def.table_owner,
2283 l_delete_def.table_name)));
2284 --add the dml
2285 ADD_ENGINE_DML(p_unit_id,
2286 l_stmt,
2287 l_delete_def.where_clause,
2288 p_priority => B_BASE_PRIORITY_DELETES,
2289 p_weight => l_weight,
2290 x_dml_id => l_dml_id);
2291
2292 --success
2293 x_weight := l_weight;
2294 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2295 RETURN TRUE;
2296 EXCEPTION
2297 WHEN OTHERS THEN
2298 MARK_OBJECT_AS_ERRORED(p_object_id,
2299 l_ctxt,
2300 SQLCODE,
2301 SQLERRM);
2302 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2303 RAISE PROGRAM_ERROR;
2304 END;
2305
2306 -- Helper to construct a DML DELETE statement and add it to a unit.
2307 FUNCTION ADD_ENGINE_UPDATE_DMLS(p_unit_id IN NUMBER,
2308 p_table_owner IN VARCHAR2,
2309 p_table_name IN VARCHAR2,
2310 p_where_clause IN VARCHAR2,
2311 px_column_map IN OUT NOCOPY b_column_name_map_type,
2312 x_logical_weight OUT NOCOPY NUMBER,
2313 x_physical_weight OUT NOCOPY NUMBER)
2314 RETURN BOOLEAN
2315 IS
2316 l_ctxt VARCHAR2(60) := PKG_NAME||'ADD_ENGINE_UPDATE_DMLS';
2317
2318 l_dml_id NUMBER;
2319
2320 l_logical_weight NUMBER := 0;
2321 l_physical_weight NUMBER := 0;
2322 l_initial_set_clause VARCHAR2(10) := ' SET ';
2323 l_set_snippet VARCHAR2(4000);
2324 l_set_clause VARCHAR2(4000);
2325 l_prefix VARCHAR2(100);
2326 l_prefix_len NUMBER;
2327 l_suffix VARCHAR2(4000);
2328 l_suffix_len NUMBER;
2329 l_column VARCHAR2(30);
2330 l_column_count NUMBER;
2331 l_table_weight NUMBER;
2332
2333 l_weight NUMBER;
2334 k NUMBER;
2335 l_msg VARCHAR2(4000);
2336 BEGIN
2337 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
2338
2339 --prep the dml prefix and suffix
2340 l_prefix := 'UPDATE '||p_table_owner||'.'||p_table_name;
2341 IF p_where_clause IS NOT NULL THEN
2342 l_suffix := ' WHERE ';
2343 IF length(l_suffix) + length(p_where_clause) > B_STMT_MAXLEN THEN
2344 l_msg := 'Table '||p_table_owner||'.'||p_table_name||' has a where clause that is too long.';
2345 fnd_oam_debug.log(3, l_ctxt, l_msg);
2346 MARK_OBJECT_AS_ERRORED(b_run.object_id,
2347 l_msg);
2348 RAISE PROGRAM_ERROR;
2349 ELSE
2350 l_suffix := l_suffix||p_where_clause;
2351 END IF;
2352 ELSE
2353 l_suffix := '';
2354 END IF;
2355 l_prefix_len := length(l_prefix);
2356 l_suffix_len := NVL(length(l_suffix), 0);
2357
2358 --get the table weight
2359 l_table_weight := FND_OAM_DSCFG_UTILS_PKG.GET_TABLE_WEIGHT(p_table_owner,
2360 p_table_name);
2361
2362 -- initialize pieces we use to identify the currently accumulating sql statement
2363 l_set_clause := l_initial_set_clause;
2364 l_column_count := 0;
2365 l_weight := l_table_weight;
2366
2367 --loop over the list of columns
2368 l_column := px_column_map.FIRST;
2369 WHILE l_column IS NOT NULL LOOP
2370 --compose the column=value snippet
2371 l_set_snippet := l_column||'='||b_dml_update_segments(px_column_map(l_column)).new_column_value;
2372 IF l_column_count <> 0 THEN
2373 l_set_snippet := ', '||l_set_snippet;
2374 END IF;
2375 --see if we have room
2376 IF l_prefix_len + length(l_set_clause) + length(l_set_snippet) + l_suffix_len <= B_STMT_MAXLEN THEN
2377 --has room, add the snippet, adjust the weight and increment our counters
2378 l_set_clause := l_set_clause||l_set_snippet;
2379 IF b_dml_update_segments(px_column_map(l_column)).weight_modifier IS NOT NULL THEN
2380 l_weight := l_weight * b_dml_update_segments(px_column_map(l_column)).weight_modifier;
2381 END IF;
2382 l_column_count := l_column_count + 1;
2383 l_column := px_column_map.NEXT(l_column);
2384 ELSE
2385 --no room left
2386 IF l_column_count = 0 THEN
2387 --no room for the first element, this is bad
2388 l_msg := 'This set clause alone is too large('||to_char(l_prefix_len + length(l_set_clause) + length(l_set_snippet) + l_suffix_len)||') for a single statement with the where clause provided.';
2389 fnd_oam_debug.log(3, l_ctxt, l_msg);
2390 MARK_OBJECT_AS_ERRORED(px_column_map(l_column),
2391 l_msg);
2392 RAISE PROGRAM_ERROR;
2393 END IF;
2394
2395 --make a dml for the currently accumulated statement, the suffix is only used to do length limitations, it is
2396 --discarded at this point and the formal where clause is passed as the other param.
2397 ADD_ENGINE_DML(p_unit_id,
2398 l_prefix||l_set_clause,
2399 p_where_clause => p_where_clause,
2400 p_priority => B_BASE_PRIORITY_UPDATES,
2401 p_weight => l_weight,
2402 x_dml_id => l_dml_id);
2403 INTEGRATE_WEIGHTS(l_logical_weight,
2404 l_physical_weight,
2405 l_weight,
2406 l_weight);
2407
2408 --re-initialize the statement variables, don't increment the column so we see it on the next loop
2409 l_set_clause := l_initial_set_clause;
2410 l_column_count := 0;
2411 l_weight := l_table_weight;
2412 END IF;
2413 END LOOP;
2414
2415 --get any remaining statement if we exited the loop with in-progress columns
2416 IF l_column_count > 0 THEN
2417 ADD_ENGINE_DML(p_unit_id,
2418 l_prefix||l_set_clause,
2419 p_where_clause => p_where_clause,
2420 p_priority => B_BASE_PRIORITY_UPDATES,
2421 p_weight => l_weight,
2422 x_dml_id => l_dml_id);
2423 INTEGRATE_WEIGHTS(l_logical_weight,
2424 l_physical_weight,
2425 l_weight,
2426 l_weight);
2427 END IF;
2428
2429 --success
2430 x_logical_weight := l_logical_weight;
2431 x_physical_weight := l_physical_weight;
2432 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2433 RETURN TRUE;
2434 EXCEPTION
2435 WHEN PROGRAM_ERROR THEN
2436 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2437 RAISE;
2438 WHEN OTHERS THEN
2439 MARK_OBJECT_AS_ERRORED(b_run.object_id,
2440 l_ctxt,
2441 SQLCODE,
2442 SQLERRM);
2443 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2444 RAISE PROGRAM_ERROR;
2445 END;
2446
2447 -- create a plsql entry for a given unit
2448 PROCEDURE ADD_ENGINE_PLSQL(p_unit_id IN NUMBER,
2449 p_plsql_text IN VARCHAR2,
2450 p_priority IN NUMBER DEFAULT NULL,
2451 p_weight IN NUMBER DEFAULT NULL,
2452 x_plsql_id OUT NOCOPY NUMBER)
2453 IS
2454 l_ctxt VARCHAR2(60) := PKG_NAME||'ADD_ENGINE_PLSQL';
2455
2456 l_plsql_id NUMBER;
2457 BEGIN
2458 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
2459
2460 INSERT INTO FND_OAM_DSCRAM_PLSQLS (PLSQL_ID,
2461 UNIT_ID,
2462 PRIORITY,
2463 WEIGHT,
2464 PLSQL_TEXT,
2465 CREATED_BY,
2466 CREATION_DATE,
2467 LAST_UPDATED_BY,
2468 LAST_UPDATE_DATE,
2469 LAST_UPDATE_LOGIN
2470 )
2471 VALUES
2472 (FND_OAM_DSCRAM_PLSQLS_S.NEXTVAL,
2473 p_unit_id,
2474 p_priority,
2475 p_weight,
2476 p_plsql_text,
2477 FND_GLOBAL.USER_ID,
2478 SYSDATE,
2479 FND_GLOBAL.USER_ID,
2480 SYSDATE,
2481 FND_GLOBAL.USER_ID)
2482 RETURNING PLSQL_ID INTO l_plsql_id;
2483
2484 x_plsql_id := l_plsql_id;
2485
2486 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2487 EXCEPTION
2488 WHEN OTHERS THEN
2489 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Exception: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
2490 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2491 RAISE;
2492 END;
2493
2494 -- Helper function to ADD_ENGINE_UNITS_FOR_DOMAIN to handle the table_bound objects of a specific domain.
2495 -- This is part of the parent's autonomous transaction and is split out primarily because it's too much
2496 -- code to include in an already large parent function. Each table owner/table_name spawns its own unit
2497 -- or set of units in the case of a concurrent_meta_unit.
2498 FUNCTION ADD_ENGINE_TABLE_BOUND_UNITS(p_task_id IN NUMBER,
2499 px_table_bound_map IN OUT NOCOPY b_table_bound_map_type,
2500 px_bound_operations_phase IN OUT NOCOPY NUMBER,
2501 x_logical_weight OUT NOCOPY NUMBER,
2502 x_physical_weight OUT NOCOPY NUMBER)
2503 RETURN BOOLEAN
2504 IS
2505 l_ctxt VARCHAR2(60) := PKG_NAME||'ADD_ENGINE_TABLE_BOUND_UNITS';
2506
2507 l_total_logical_weight NUMBER := 0;
2508 l_total_physical_weight NUMBER := 0;
2509 l_unit_logical_weight NUMBER;
2510 l_unit_physical_weight NUMBER;
2511 l_logical_weight NUMBER;
2512 l_physical_weight NUMBER;
2513
2514 l_table_objects_def b_table_objects_def_type; --allocate a new one using it's create each time
2515 l_unit_id NUMBER;
2516 l_dml_unit_id NUMBER;
2517 l_plsql_unit_id NUMBER;
2518 l_table_name VARCHAR2(30);
2519 l_table_owner VARCHAR2(30);
2520 l_has_dmls BOOLEAN;
2521 l_has_plsqls BOOLEAN;
2522 l_plsql_id NUMBER;
2523 l_where_clause VARCHAR2(4000);
2524 l_weight NUMBER;
2525 k NUMBER;
2526 j NUMBER;
2527 BEGIN
2528 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
2529
2530 -- Go through each owner/name
2531 -- combo and create units. For now, each owner/name combo will produce one unit in a different phase. Other tables
2532 -- in the same domain usually means overlap so they'd need a different phase anyhow. Lumping all the operations
2533 -- on one table into a single unit is ok because if they want seperation, they should specify a different primary_domain.
2534 -- Finally, use and increment the passed in phases for each instead of using NULLs to keep NULL open for any ops the user
2535 -- wants to have run at the very end.
2536 l_table_owner := px_table_bound_map.FIRST;
2537 WHILE l_table_owner IS NOT NULL LOOP
2538 fnd_oam_debug.log(1, l_ctxt, 'Processing Table Owner: '||l_table_owner);
2539 --loop over the table names for this owner
2540 l_table_name := px_table_bound_map(l_table_owner).FIRST;
2541 WHILE l_table_name IS NOT NULL LOOP
2542 fnd_oam_debug.log(1, l_ctxt, 'Processing Table Name: '||l_table_name);
2543 --get a reference to the table_objects_def
2544 l_table_objects_def := px_table_bound_map(l_table_owner)(l_table_name);
2545
2546 --see if we've got dmls and plsqls, this requires a concurrent unit
2547 l_has_dmls := (l_table_objects_def.update_map.COUNT > 0) OR (l_table_objects_def.delete_map.COUNT > 0);
2548 l_has_plsqls := (l_table_objects_def.plsqls.COUNT > 0);
2549 l_unit_logical_weight := 0;
2550 l_unit_physical_weight := 0;
2551
2552 IF l_has_dmls AND l_has_plsqls THEN
2553 --get an id for the concurrent meta-unit, otherwise tag it with a NULL
2554 l_unit_id := GET_NEXT_UNIT_ID;
2555 ELSE
2556 l_unit_id := NULL;
2557 END IF;
2558 IF l_has_dmls THEN
2559 l_dml_unit_id := GET_NEXT_UNIT_ID;
2560 END IF;
2561 IF l_has_plsqls THEN
2562 l_plsql_unit_id := GET_NEXT_UNIT_ID;
2563 END IF;
2564
2565 --create DMLs for each update where clause, can't loop on WHILE because we allow NULL keys
2566 j := l_table_objects_def.update_map.COUNT;
2567 l_where_clause := l_table_objects_def.update_map.FIRST;
2568 FOR k IN 1..j LOOP
2569 IF ADD_ENGINE_UPDATE_DMLS(l_dml_unit_id,
2570 l_table_owner,
2571 l_table_name,
2572 l_where_clause,
2573 l_table_objects_def.update_map(l_where_clause),
2574 l_logical_weight,
2575 l_physical_weight) THEN
2576 INTEGRATE_WEIGHTS(l_unit_logical_weight,
2577 l_unit_physical_weight,
2578 l_logical_weight,
2579 l_physical_weight);
2580 END IF;
2581 l_where_clause := l_table_objects_def.update_map.NEXT(l_where_clause);
2582 END LOOP;
2583
2584 --create DMLs for each delete where clause, can't loop on WHILE because we allow NULL keys
2585 j := l_table_objects_def.delete_map.COUNT;
2586 l_where_clause := l_table_objects_def.delete_map.FIRST;
2587 FOR k IN 1..j LOOP
2588 IF ADD_ENGINE_DELETE_DML(l_dml_unit_id,
2589 l_table_objects_def.delete_map(l_where_clause),
2590 l_weight) THEN
2591 INTEGRATE_WEIGHTS(l_unit_logical_weight,
2592 l_unit_physical_weight,
2593 l_weight,
2594 l_weight);
2595 END IF;
2596 l_where_clause := l_table_objects_def.delete_map.NEXT(l_where_clause);
2597 END LOOP;
2598
2599 --create plsqls for each table bound plsql
2600 j := l_table_objects_def.plsqls.FIRST;
2601 WHILE j IS NOT NULL LOOP
2602 k := l_table_objects_def.plsqls(j);
2603 --no need for a checked return value, throws an exception if it fails
2604 ADD_ENGINE_PLSQL(l_plsql_unit_id,
2605 b_plsql_texts(k).plsql_text,
2606 p_weight => b_plsql_texts(k).weight,
2607 x_plsql_id => l_plsql_id);
2608
2609 INTEGRATE_WEIGHTS(l_unit_logical_weight,
2610 l_unit_physical_weight,
2611 b_plsql_texts(k).weight,
2612 b_plsql_texts(k).weight);
2613 j := l_table_objects_def.plsqls.NEXT(j);
2614 END LOOP;
2615
2616 --create the necessary units
2617 IF l_unit_id IS NOT NULL THEN
2618 --concurrent_units case
2619 ADD_ENGINE_UNIT(p_task_id,
2620 FND_OAM_DSCRAM_UTILS_PKG.G_UNIT_TYPE_CONC_GROUP,
2621 p_phase => px_bound_operations_phase,
2622 p_weight => l_unit_logical_weight,
2623 p_unit_object_owner => l_table_owner,
2624 p_unit_object_name => l_table_name,
2625 px_unit_id => l_unit_id);
2626 -- create child units, weight and phase are meaningless here
2627 IF l_dml_unit_id IS NOT NULL THEN
2628 ADD_ENGINE_UNIT(p_task_id,
2629 FND_OAM_DSCRAM_UTILS_PKG.G_UNIT_TYPE_DML_SET,
2630 p_concurrent_group_unit_id => l_unit_id,
2631 px_unit_id => l_dml_unit_id);
2632 END IF;
2633 IF l_plsql_unit_id IS NOT NULL THEN
2634 ADD_ENGINE_UNIT(p_task_id,
2635 FND_OAM_DSCRAM_UTILS_PKG.G_UNIT_TYPE_PLSQL_SET,
2636 p_concurrent_group_unit_id => l_unit_id,
2637 px_unit_id => l_plsql_unit_id);
2638 END IF;
2639 ELSE
2640 --create topmost unit depending on which unit_id isn't null
2641 IF l_dml_unit_id IS NOT NULL THEN
2642 ADD_ENGINE_UNIT(p_task_id,
2643 FND_OAM_DSCRAM_UTILS_PKG.G_UNIT_TYPE_DML_SET,
2644 p_phase => px_bound_operations_phase,
2645 p_weight => l_unit_logical_weight,
2646 p_unit_object_owner => l_table_owner,
2647 p_unit_object_name => l_table_name,
2648 px_unit_id => l_dml_unit_id);
2649 ELSIF l_plsql_unit_id IS NOT NULL THEN
2650 ADD_ENGINE_UNIT(p_task_id,
2651 FND_OAM_DSCRAM_UTILS_PKG.G_UNIT_TYPE_PLSQL_SET,
2652 p_phase => px_bound_operations_phase,
2653 p_weight => l_unit_logical_weight,
2654 p_unit_object_owner => l_table_owner,
2655 p_unit_object_name => l_table_name,
2656 px_unit_id => l_plsql_unit_id);
2657 END IF;
2658 END IF;
2659
2660 --increment the phase
2661 px_bound_operations_phase := px_bound_operations_phase + B_PHASE_INCREMENT;
2662
2663 fnd_oam_debug.log(1, l_ctxt, 'Unit logical/physical weight: ('||l_unit_logical_weight||')('||l_unit_physical_weight||')');
2664 --integrate the unit's logical/physical weights
2665 INTEGRATE_WEIGHTS(l_total_logical_weight,
2666 l_total_physical_weight,
2667 l_unit_logical_weight,
2668 l_unit_physical_weight);
2669
2670 l_table_name := px_table_bound_map(l_table_owner).NEXT(l_table_name);
2671 END LOOP;
2672 l_table_owner := px_table_bound_map.NEXT(l_table_owner);
2673 END LOOP;
2674
2675 COMMIT;
2676
2677 --success
2678 x_logical_weight := l_total_logical_weight;
2679 x_physical_weight := l_total_physical_weight;
2680 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2681 RETURN TRUE;
2682 EXCEPTION
2683 WHEN PROGRAM_ERROR THEN
2684 ROLLBACK;
2685 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2686 RAISE;
2687 WHEN OTHERS THEN
2688 ROLLBACK;
2689 --mark the run becaues we have no place better.
2690 MARK_OBJECT_AS_ERRORED(b_run.object_id,
2691 l_ctxt,
2692 SQLCODE,
2693 SQLERRM);
2694 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
2695 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
2696 RAISE;
2697 END;
2698
2699 -- Private, helper to COMPILE_CONFIG_INSTANCE to dump out tasks/units for a specific primary domain.
2700 FUNCTION ADD_ENGINE_UNITS_FOR_DOMAIN(p_task_id IN NUMBER,
2701 p_primary_domain IN VARCHAR2,
2702 px_truncate_phase IN OUT NOCOPY NUMBER,
2703 px_unbound_plsql_phase IN OUT NOCOPY NUMBER,
2704 px_bound_operations_phase IN OUT NOCOPY NUMBER,
2705 x_logical_weight OUT NOCOPY NUMBER,
2706 x_physical_weight OUT NOCOPY NUMBER)
2707 RETURN BOOLEAN
2708 IS
2709 PRAGMA AUTONOMOUS_TRANSACTION;
2710
2711 l_ctxt VARCHAR2(60) := PKG_NAME||'ADD_ENGINE_UNITS_FOR_DOMAIN';
2712
2713 --Types used to dup-check truncates for a domain
2714 --Hash Table of table_name->truncate object_id
2715 TYPE l_truncate_table_name_map_t IS TABLE OF NUMBER INDEX BY VARCHAR2(30);
2716 --Hash Table of owner_name->table_name map
2717 TYPE l_truncate_table_owner_map_t IS TABLE OF l_truncate_table_name_map_t INDEX BY VARCHAR2(30);
2718
2719 --temporarily collect truncates into this map
2720 l_truncate_table_owner_map l_truncate_table_owner_map_t;
2721
2722 --collect table_bound objects in the domain into this map to pass to ADD_ENGINE_TABLE_BOUND_UNITS
2723 l_table_bound_map b_table_bound_map_type;
2724
2725 --counters for the weight of this domain
2726 l_domain_logical_weight NUMBER := 0;
2727 l_domain_physical_weight NUMBER := 0;
2728
2729 --temporary structures/variables
2730 l_table_objects_def b_table_objects_def_type; --allocate a new one using it's create each time
2731 l_column_map b_column_name_map_type;
2732 l_segment b_dml_update_segment_def_type;
2733 l_delete_stmt b_dml_delete_stmt_def_type;
2734 l_truncate_stmt b_dml_truncate_stmt_def_type;
2735 l_plsql b_plsql_text_def_type;
2736 l_truncate_table_name_map l_truncate_table_name_map_t;
2737
2738 l_object_id NUMBER;
2739 l_object_id2 NUMBER;
2740 l_unit_id NUMBER;
2741 l_dml_id NUMBER;
2742 l_plsql_id NUMBER;
2743 l_weight NUMBER;
2744 l_table_owner VARCHAR2(30);
2745 l_table_name VARCHAR2(30);
2746 l_where_clause VARCHAR2(4000);
2747 l_logical_weight NUMBER;
2748 l_physical_weight NUMBER;
2749 k NUMBER;
2750 BEGIN
2751 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
2752
2753 -- loop through the domain's contents, grouping the objects
2754 k := b_primary_domains(p_primary_domain).FIRST;
2755 WHILE k IS NOT NULL LOOP
2756 l_object_id := b_primary_domains(p_primary_domain)(k);
2757 fnd_oam_debug.log(1, l_ctxt, 'Parsing object_id: '||l_object_id||'('||b_objects(l_object_id).object_type||')');
2758 --case the object type
2759 CASE b_objects(l_object_id).object_type
2760 WHEN FND_OAM_DSCFG_API_PKG.G_OTYPE_DML_UPDATE_SEGMENT THEN
2761 l_segment := b_dml_update_segments(l_object_id);
2762
2763 --get the table_objects_def reference to update
2764 l_table_objects_def := GET_TABLE_OBJECTS_DEF(l_table_bound_map,
2765 l_segment.table_owner,
2766 l_segment.table_name);
2767
2768 --ADD this update segment to the table_objects_def if it doesn't conflict
2769
2770 --see if the where clause exists
2771 l_where_clause := NVL(l_segment.where_clause, '');
2772 IF l_table_objects_def.update_map.EXISTS(l_where_clause) THEN
2773 --see if the column name's been seen before
2774 IF l_table_objects_def.update_map(l_where_clause).EXISTS(l_segment.column_name) THEN
2775 --see if the values are the same, if not this is a conflict otherwise it's just a dupe
2776 l_object_id2 := l_table_objects_def.update_map(l_where_clause)(l_segment.column_name);
2777 IF (b_dml_update_segments(l_object_id2).new_column_value <> l_segment.new_column_value) THEN
2778 MARK_OBJECT_AS_ERRORED(l_object_id,
2779 'New Column Value conflicts with Object ID: '||l_object_id2);
2780 ELSE
2781 MARK_OBJECT_WITH_WARNING(l_object_id,
2782 l_ctxt,
2783 'Duplicate of Object ID: '||l_object_id2);
2784 END IF;
2785 ELSE
2786 --new column_name
2787 l_table_objects_def.update_map(l_where_clause)(l_segment.column_name) := l_object_id;
2788 END IF;
2789 ELSE
2790 --new where clause
2791 l_column_map.DELETE;
2792 l_column_map(l_segment.column_name) := l_object_id;
2793 l_table_objects_def.update_map(l_where_clause) := l_column_map;
2794 END IF;
2795
2796 --set the table_objects_def back
2797 l_table_bound_map(l_segment.table_owner)(l_segment.table_name) := l_table_objects_def;
2798 WHEN FND_OAM_DSCFG_API_PKG.G_OTYPE_DML_DELETE_STMT THEN
2799 l_delete_stmt := b_dml_delete_stmts(l_object_id);
2800
2801 --get the table_objects_def reference to update
2802 l_table_objects_def := GET_TABLE_OBJECTS_DEF(l_table_bound_map,
2803 l_delete_stmt.table_owner,
2804 l_delete_stmt.table_name);
2805
2806 --ADD this update segment to the table_objects_def if it doesn't conflict
2807
2808 --see if the where clause exists
2809 l_where_clause := NVL(l_delete_stmt.where_clause, '');
2810 IF l_table_objects_def.delete_map.EXISTS(l_where_clause) THEN
2811 --can't delete the same table/where clause twice, mark it as a dupe
2812 MARK_OBJECT_WITH_WARNING(l_object_id,
2813 l_ctxt,
2814 'Duplicate of Object ID: '||l_table_objects_def.delete_map(l_where_clause));
2815 ELSE
2816 --add it
2817 fnd_oam_debug.log(1, l_ctxt, 'New where clause');
2818 l_table_objects_def.delete_map(NVL(l_where_clause, '')) := l_object_id;
2819 END IF;
2820
2821 --set the table_objects_def back
2822 l_table_bound_map(l_delete_stmt.table_owner)(l_delete_stmt.table_name) := l_table_objects_def;
2823 WHEN FND_OAM_DSCFG_API_PKG.G_OTYPE_DML_TRUNCATE_STMT THEN
2824 l_truncate_stmt := b_dml_truncate_stmts(l_object_id);
2825
2826 --if the run mode isn't normal, truncates need to become deletes so they can be rolled back
2827 IF b_run.run_mode <> FND_OAM_DSCRAM_UTILS_PKG.G_MODE_NORMAL THEN
2828 --since these deletes can take a long time, give a more accurate perf viewpoint by just skipping
2829 --the truncate
2830 MARK_OBJECT_WITH_WARNING(l_object_id,
2831 l_ctxt,
2832 'Skipping Truncate operation because of run mode: '||b_run.run_mode);
2833 /*
2834 --convert this truncate to a delete
2835 --get the table_objects_def reference to update
2836 l_table_objects_def := GET_TABLE_OBJECTS_DEF(l_table_bound_map,
2837 l_truncate_stmt.table_owner,
2838 l_truncate_stmt.table_name);
2839
2840 --ADD this delete segment to the table_objects_def if it doesn't conflict
2841
2842 --see if an entry exists for a NULL where clause
2843 IF l_table_objects_def.delete_map.EXISTS(NULL) THEN
2844 --can't delete the same table/where clause twice, mark it as a dupe
2845 MARK_OBJECT_WITH_WARNING(l_object_id,
2846 l_ctxt,
2847 'Duplicate of Object ID: '||l_table_objects_def.delete_map(NULL));
2848 ELSE
2849 --add it
2850 l_table_objects_def.delete_map(NULL) := l_object_id;
2851 END IF;
2852
2853 --set the table_objects_def back
2854 l_table_bound_map(l_truncate_stmt.table_owner)(l_truncate_stmt.table_name) := l_table_objects_def;
2855 */
2856 ELSE
2857 --instead of creating the truncate right away, look for a dup in the truncate_owner_map, store non-dups
2858 --in this struct for processing outside of this domain objects loop.
2859 IF l_truncate_table_owner_map.EXISTS(l_truncate_stmt.table_owner) THEN
2860 IF l_truncate_table_owner_map(l_truncate_stmt.table_owner).EXISTS(l_truncate_stmt.table_name) THEN
2861 --dupe
2862 MARK_OBJECT_WITH_WARNING(l_object_id,
2863 l_ctxt,
2864 'Duplicate of Object ID: '||l_truncate_table_owner_map(l_truncate_stmt.table_owner)(l_truncate_stmt.table_name));
2865 ELSE
2866 --new table name
2867 l_truncate_table_owner_map(l_truncate_stmt.table_owner)(l_truncate_stmt.table_name) := l_object_id;
2868 END IF;
2869 ELSE
2870 --new owner
2871 l_truncate_table_name_map.DELETE;
2872 l_truncate_table_name_map(l_truncate_stmt.table_name) := l_object_id;
2873 l_truncate_table_owner_map(l_truncate_stmt.table_owner) := l_truncate_table_name_map;
2874 END IF;
2875
2876 END IF;
2877 WHEN FND_OAM_DSCFG_API_PKG.G_OTYPE_PLSQL_TEXT THEN
2878 l_plsql := b_plsql_texts(l_object_id);
2879
2880 --see if we've got a table owner and name, meaning the pl/sql is table bound
2881 IF l_plsql.table_owner IS NOT NULL and l_plsql.table_name IS NOT NULL THEN
2882 --get the table_objects_def reference to update
2883 l_table_objects_def := GET_TABLE_OBJECTS_DEF(l_table_bound_map,
2884 l_plsql.table_owner,
2885 l_plsql.table_name);
2886
2887 --ADD this plsql to the list of plsqls
2888
2889 l_table_objects_def.plsqls.EXTEND;
2890 l_table_objects_def.plsqls(l_table_objects_def.plsqls.COUNT) := l_object_id;
2891
2892 --set the table_objects_def back
2893 l_table_bound_map(l_plsql.table_owner)(l_plsql.table_name) := l_table_objects_def;
2894 ELSE
2895 --unbound pl/sql, run in phases after truncate and also can't be split
2896 BEGIN
2897 l_unit_id := NULL;
2898 ADD_ENGINE_UNIT(p_task_id,
2899 FND_OAM_DSCRAM_UTILS_PKG.G_UNIT_TYPE_PLSQL_SET,
2900 p_phase => px_unbound_plsql_phase,
2901 p_weight => l_plsql.weight,
2902 p_disable_splitting => FND_API.G_TRUE,
2903 px_unit_id => l_unit_id);
2904
2905 --and its corresponding PL/SQL
2906 ADD_ENGINE_PLSQL(l_unit_id,
2907 l_plsql.plsql_text,
2908 p_weight => l_plsql.weight,
2909 x_plsql_id => l_plsql_id);
2910
2911 --increment the unbound plsql phase
2912 px_unbound_plsql_phase := px_unbound_plsql_phase + B_PHASE_INCREMENT;
2913 INTEGRATE_WEIGHTS(l_domain_logical_weight,
2914 l_domain_physical_weight,
2915 l_plsql.weight,
2916 l_plsql.weight);
2917 EXCEPTION
2918 WHEN OTHERS THEN
2919 --put the error in the object and move on
2920 MARK_OBJECT_AS_ERRORED(l_object_id,
2921 l_ctxt,
2922 SQLCODE,
2923 SQLERRM);
2924 END;
2925 END IF;
2926 ELSE
2927 --unmatched object type, shouldn't happen
2928 fnd_oam_debug.log(6, l_ctxt, 'Unknown Object Type: '||b_objects(l_object_id).object_type);
2929 RAISE PROGRAM_ERROR;
2930 END CASE;
2931
2932 k := b_primary_domains(p_primary_domain).NEXT(k);
2933 END LOOP;
2934
2935 --loop over the truncates, create solo units for each
2936 l_table_owner := l_truncate_table_owner_map.FIRST;
2937 WHILE l_table_owner IS NOT NULL LOOP
2938 l_table_name := l_truncate_table_owner_map(l_table_owner).FIRST;
2939 WHILE l_table_name IS NOT NULL LOOP
2940 l_object_id := l_truncate_table_owner_map(l_table_owner)(l_table_name);
2941 l_truncate_stmt := b_dml_truncate_stmts(l_object_id);
2942
2943 --figure out the true weight to use
2944 l_weight := CEIL(NVL(l_truncate_stmt.weight, B_TRUNCATE_WEIGHT_MODIFIER *
2945 FND_OAM_DSCFG_UTILS_PKG.GET_TABLE_WEIGHT(l_table_owner,
2946 l_table_name)));
2947 BEGIN
2948 l_unit_id := NULL;
2949 --even though truncates don't use AD splitting, store the unit object owner/name to simplify reporting
2950 ADD_ENGINE_UNIT(p_task_id,
2951 FND_OAM_DSCRAM_UTILS_PKG.G_UNIT_TYPE_DML_SET,
2952 p_phase => px_truncate_phase,
2953 p_weight => l_weight,
2954 p_unit_object_owner => l_table_owner,
2955 p_unit_object_name => l_table_name,
2956 p_disable_splitting => FND_API.G_TRUE,
2957 px_unit_id => l_unit_id);
2958
2959 --and its corresponding DML
2960 --TODO: See if the PURGE MATERIALIZED VIEW LOG option is acceptable here
2961 ADD_ENGINE_DML(l_unit_id,
2962 'TRUNCATE TABLE '||l_table_owner||'.'||l_table_name,
2963 p_weight => l_weight,
2964 x_dml_id => l_dml_id);
2965
2966 --increment the truncate phase and update the weight counters
2967 px_truncate_phase := px_truncate_phase + B_PHASE_INCREMENT;
2968 INTEGRATE_WEIGHTS(l_domain_logical_weight,
2969 l_domain_physical_weight,
2970 l_weight,
2971 l_weight);
2972 EXCEPTION
2973 WHEN OTHERS THEN
2974 --put the error in the object and move on
2975 MARK_OBJECT_AS_ERRORED(l_object_id,
2976 l_ctxt,
2977 SQLCODE,
2978 SQLERRM);
2979 END;
2980 l_table_name := l_truncate_table_owner_map(l_table_owner).NEXT(l_table_name);
2981 END LOOP;
2982 l_table_owner := l_truncate_table_owner_map.NEXT(l_table_owner);
2983 END LOOP;
2984
2985 -- split out the logic to create the table bound units and integrate their collective weight into the domain's
2986 -- overall weight.
2987 IF ADD_ENGINE_TABLE_BOUND_UNITS(p_task_id,
2988 l_table_bound_map,
2989 px_bound_operations_phase,
2990 l_logical_weight,
2991 l_physical_weight) THEN
2992 INTEGRATE_WEIGHTS(l_domain_logical_weight,
2993 l_domain_physical_weight,
2994 l_logical_weight,
2995 l_physical_weight);
2996 END IF;
2997
2998 COMMIT;
2999
3000 --success
3001 fnd_oam_debug.log(1, l_ctxt, 'Domain logical/physical weights: ('||l_domain_logical_weight||')('||l_domain_physical_weight||')');
3002 x_logical_weight := l_domain_logical_weight;
3003 x_physical_weight := l_domain_physical_weight;
3004 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3005 RETURN TRUE;
3006 EXCEPTION
3007 WHEN PROGRAM_ERROR THEN
3008 ROLLBACK;
3009 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3010 RAISE;
3011 WHEN OTHERS THEN
3012 ROLLBACK;
3013 --mark the run becaues we have no place better.
3014 MARK_OBJECT_AS_ERRORED(b_run.object_id,
3015 l_ctxt,
3016 SQLCODE,
3017 SQLERRM);
3018 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
3019 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3020 RAISE;
3021 END;
3022
3023 -- To support multiple bundles/bundle work partitioning, use this call to encapsulate the
3024 -- assignment of a task to a bundle based on whatever scheme we figure is best. Returns the object_id
3025 -- of the bundle_metadata object.
3026 -- Invariant: b_bundles_metadata has at least one entry by now
3027 FUNCTION GET_BUNDLE_FOR_GROUP(p_group b_dependency_group_def_type)
3028 RETURN NUMBER
3029 IS
3030 l_least_weight_id NUMBER := NULL;
3031 l_least_weight NUMBER := NULL;
3032 l_least_count_id NUMBER := NULL;
3033 l_least_count NUMBER := NULL;
3034
3035 k NUMBER;
3036 BEGIN
3037 --skip assignment if there's only one, the common case
3038 IF b_bundles.COUNT > 1 THEN
3039 --find the bundle with the least physical_weight
3040 k := b_bundles.FIRST;
3041 WHILE k IS NOT NULL LOOP
3042 IF l_least_weight IS NULL OR b_bundles(k).assigned_physical_weight < l_least_weight THEN
3043 l_least_weight := b_bundles(k).assigned_physical_weight;
3044 l_least_weight_id := k;
3045 END IF;
3046 IF l_least_count IS NULL OR b_bundles(k).assigned_task_count < l_least_count THEN
3047 l_least_count := b_bundles(k).assigned_task_count;
3048 l_least_count_id := k;
3049 END IF;
3050 k := b_bundles.NEXT(k);
3051 END LOOP;
3052
3053 --if the least weight is > 0, use it - otherwise use the least count which we know is incrementing.
3054 IF l_least_weight > 0 THEN
3055 RETURN l_least_weight_id;
3056 ELSE
3057 RETURN l_least_count_id;
3058 END IF;
3059 ELSE
3060 --only one bundle, return it's id
3061 RETURN b_bundles.FIRST;
3062 END IF;
3063 END;
3064
3065 -- Private, helper to GENERATE_ENGINE_TASKS to dump out tasks/units for a specific dependency group
3066 FUNCTION ADD_ENGINE_TASK_WITH_UNITS(p_group_id IN NUMBER)
3067 RETURN BOOLEAN
3068 IS
3069 PRAGMA AUTONOMOUS_TRANSACTION;
3070
3071 l_ctxt VARCHAR2(60) := PKG_NAME||'ADD_ENGINE_TASK_WITH_UNITS';
3072
3073 l_bundle_object_id NUMBER;
3074 l_task_id NUMBER;
3075 l_truncate_phase NUMBER := B_BASE_PHASE_TRUNCATES;
3076 l_unbound_plsql_phase NUMBER := B_BASE_PHASE_UNBOUND_PLSQLS;
3077 l_bound_operations_phase NUMBER := B_BASE_PHASE_BOUND_OPERATIONS;
3078 l_task_logical_weight NUMBER := 0;
3079 l_task_physical_weight NUMBER := 0;
3080
3081 l_domain VARCHAR2(120);
3082 l_weight NUMBER;
3083 l_logical_weight NUMBER;
3084 l_physical_weight NUMBER;
3085
3086 k NUMBER;
3087 j NUMBER;
3088 l_msg VARCHAR2(4000);
3089 BEGIN
3090 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
3091
3092 -- fetch a task_id to use for creating units
3093 SELECT FND_OAM_DSCRAM_TASKS_S.NEXTVAL
3094 INTO l_task_id
3095 FROM dual;
3096 b_dependency_groups(p_group_id).task_id := l_task_id;
3097 fnd_oam_debug.log(1, l_ctxt, 'Using task_id: '||l_task_id);
3098
3099 -- loop through the primary domains, creating units for each kind of object in each domain - we don't allow
3100 -- collecting objects across primary domains.
3101 k := b_dependency_groups(p_group_id).primary_domains.FIRST;
3102 WHILE k IS NOT NULL LOOP
3103 l_domain := b_dependency_groups(p_group_id).primary_domains(k);
3104 fnd_oam_debug.log(1, l_ctxt, 'Processing primary_domain: '||l_domain);
3105 --for a given domain, create the units, only do weight calculation if it came back true for sucess.
3106 IF ADD_ENGINE_UNITS_FOR_DOMAIN(l_task_id,
3107 l_domain,
3108 l_truncate_phase,
3109 l_unbound_plsql_phase,
3110 l_bound_operations_phase,
3111 l_logical_weight,
3112 l_physical_weight) THEN
3113 --only integrate the logical_weight, physical_weight if user hasn't supplied a weight
3114 IF b_dependency_groups(p_group_id).weight IS NULL THEN
3115 INTEGRATE_WEIGHTS(l_task_logical_weight,
3116 l_task_physical_weight,
3117 l_logical_weight,
3118 l_physical_weight);
3119 END IF;
3120 END IF;
3121
3122 k := b_dependency_groups(p_group_id).primary_domains.NEXT(k);
3123 END LOOP;
3124
3125 fnd_oam_debug.log(1, l_ctxt, 'Task logical/physical weights: ('||l_task_logical_weight||')('||l_task_physical_weight||')');
3126 -- now that we've composed the task components, figure out what bundle to give it to and make the task
3127 fnd_oam_debug.log(1, l_ctxt, 'Getting bundle for group...');
3128 l_bundle_object_id := GET_BUNDLE_FOR_GROUP(b_dependency_groups(p_group_id));
3129 fnd_oam_debug.log(1, l_ctxt, 'Using Bundle_id: '||b_bundles(l_bundle_object_id).bundle_id);
3130 l_weight := NVL(b_dependency_groups(p_group_id).weight, l_task_logical_weight);
3131 fnd_oam_debug.log(1, l_ctxt, 'Using Task Weight: '||l_weight);
3132
3133 --skip the PRIORITY column for now
3134 INSERT INTO FND_OAM_DSCRAM_TASKS (TASK_ID,
3135 BUNDLE_ID,
3136 TASK_STATUS,
3137 WEIGHT,
3138 WORKERS_ASSIGNED,
3139 CREATED_BY,
3140 CREATION_DATE,
3141 LAST_UPDATED_BY,
3142 LAST_UPDATE_DATE,
3143 LAST_UPDATE_LOGIN
3144 )
3145 VALUES
3146 (l_task_id,
3147 b_bundles(l_bundle_object_id).bundle_id,
3148 FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_UNPROCESSED,
3149 l_weight,
3150 0,
3151 FND_GLOBAL.USER_ID,
3152 SYSDATE,
3153 FND_GLOBAL.USER_ID,
3154 SYSDATE,
3155 FND_GLOBAL.USER_ID);
3156
3157 --update the bundle's assigned weight and task count
3158 b_bundles(l_bundle_object_id).assigned_task_count := b_bundles(l_bundle_object_id).assigned_task_count + 1;
3159 b_bundles(l_bundle_object_id).assigned_physical_weight := b_bundles(l_bundle_object_id).assigned_physical_weight + NVL(l_weight, l_task_physical_weight);
3160
3161 COMMIT;
3162
3163 --success
3164 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3165 RETURN TRUE;
3166 EXCEPTION
3167 WHEN PROGRAM_ERROR THEN
3168 ROLLBACK;
3169 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3170 --quick fail, cause other tasks to skip so we can write the error somewhere
3171 RAISE;
3172 WHEN OTHERS THEN
3173 ROLLBACK;
3174 --mark the run object
3175 MARK_OBJECT_AS_ERRORED(b_run.object_id,
3176 l_ctxt,
3177 SQLCODE,
3178 SQLERRM);
3179 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
3180 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3181 RAISE PROGRAM_ERROR;
3182 END;
3183
3184 -- Private, helper to COMPILE_CONFIG_INSTANCE to dump out tasks/units
3185 PROCEDURE GENERATE_ENGINE_TASKS
3186 IS
3187 l_ctxt VARCHAR2(60) := PKG_NAME||'GENERATE_ENGINE_TASKS';
3188
3189 l_group_id NUMBER;
3190 l_ignore BOOLEAN;
3191
3192 k NUMBER;
3193 BEGIN
3194 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
3195
3196 -- loop through the dependency groups
3197 l_group_id := b_dependency_groups.FIRST;
3198 WHILE l_group_id IS NOT NULL LOOP
3199 --TODO: come up with a way to identify a task we've already compiled.
3200 --Problem: group_ids are transient and can be totally different based on the domain distribution. re-compiling
3201 --and trying to match them up would require a full task comparison?
3202 --For now, just create a new task for each dependency group
3203 fnd_oam_debug.log(1, l_ctxt, 'Adding Task for group_id: '||l_group_id);
3204 l_ignore := ADD_ENGINE_TASK_WITH_UNITS(l_group_id);
3205
3206 l_group_id := b_dependency_groups.NEXT(l_group_id);
3207 END LOOP;
3208
3209 --success
3210 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3211 EXCEPTION
3212 WHEN PROGRAM_ERROR THEN
3213 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3214 RAISE;
3215 WHEN OTHERS THEN
3216 --mark the run object
3217 MARK_OBJECT_AS_ERRORED(b_run.object_id,
3218 l_ctxt,
3219 SQLCODE,
3220 SQLERRM);
3221 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
3222 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3223 RAISE PROGRAM_ERROR;
3224 END;
3225
3226 -- Private, helper to COMPILE_CONFIG_INSTANCE to write the updated weight of the run/bundles to the db.
3227 PROCEDURE UPDATE_RUN_BUNDLE_WEIGHTS
3228 IS
3229 PRAGMA AUTONOMOUS_TRANSACTION;
3230
3231 l_ctxt VARCHAR2(60) := PKG_NAME||'UPDATE_RUN_BUNDLE_WEIGHTS';
3232 l_weight NUMBER;
3233 k NUMBER;
3234 BEGIN
3235 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
3236
3237 k := b_bundles.FIRST;
3238 WHILE k IS NOT NULL LOOP
3239 l_weight := NVL(b_bundles(k).weight, b_bundles(k).assigned_physical_weight);
3240 --add this bundle's weight to the run's assigned_physical_weight
3241 b_run.assigned_physical_weight := b_run.assigned_physical_weight + l_weight;
3242 fnd_oam_debug.log(1, l_ctxt, 'Updating bundle_id('||b_bundles(k).bundle_id||') weight('||l_weight||')');
3243 UPDATE fnd_oam_dscram_bundles
3244 SET weight = l_weight
3245 WHERE bundle_id = b_bundles(k).bundle_id;
3246 k := b_bundles.NEXT(k);
3247 END LOOP;
3248
3249 l_weight := NVL(b_run.weight, b_run.assigned_physical_weight);
3250 fnd_oam_debug.log(1, l_ctxt, 'Updating run_id('||b_run.run_id||') weight ('||l_weight||')');
3251 UPDATE fnd_oam_dscram_runs_b
3252 SET weight = l_weight
3253 WHERE run_id = b_run.run_id;
3254
3255 COMMIT;
3256
3257 --success
3258 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3259 EXCEPTION
3260 WHEN OTHERS THEN
3261 ROLLBACK;
3262 MARK_OBJECT_AS_ERRORED(b_run.object_id,
3263 l_ctxt,
3264 SQLCODE,
3265 SQLERRM);
3266 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
3267 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3268 RAISE PROGRAM_ERROR;
3269 END;
3270
3271 -- Private, helper to COMPILE_CONFIG_INSTANCE to write dirty objects to the db.
3272 PROCEDURE WRITE_DIRTY_OBJECTS
3273 IS
3274 PRAGMA AUTONOMOUS_TRANSACTION;
3275
3276 l_ctxt VARCHAR2(60) := PKG_NAME||'WRITE_DIRTY_OBJECTS';
3277
3278 k NUMBER;
3279 l_error_found BOOLEAN := FALSE;
3280 BEGIN
3281 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
3282
3283 --TODO: see if we can make this bulk
3284 --TODO: need to write the target_type/target_id at some point - probably requires many changes.
3285 k := b_objects.FIRST;
3286 WHILE k IS NOT NULL LOOP
3287 IF b_objects(k).is_dirty THEN
3288 --all objects in b_objects should have db objects already created so just try to update
3289 BEGIN
3290 UPDATE fnd_oam_dscfg_objects
3291 SET errors_found_flag = b_objects(k).new_errors_found_flag,
3292 message = b_objects(k).new_message,
3293 target_type = b_objects(k).target_type,
3294 target_id = b_objects(k).target_id,
3295 last_update_date = SYSDATE,
3296 last_updated_by = FND_GLOBAL.USER_ID,
3297 last_update_login = FND_GLOBAL.USER_ID
3298 WHERE object_id = b_objects(k).object_id;
3299 EXCEPTION
3300 WHEN OTHERS THEN
3301 fnd_oam_debug.log(3, l_ctxt, 'While writing object_id('||b_objects(k).object_id||'): Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
3302 l_error_found := TRUE;
3303 END;
3304 END IF;
3305 k := b_objects.NEXT(k);
3306 END LOOP;
3307
3308 --commit whatever we could do
3309 COMMIT;
3310
3311 --raise an error if we couldn't write something
3312 IF l_error_found THEN
3313 RAISE STORAGE_ERROR;
3314 END IF;
3315
3316 --success
3317 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3318 EXCEPTION
3319 WHEN STORAGE_ERROR THEN
3320 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3321 RAISE;
3322 WHEN OTHERS THEN
3323 ROLLBACK;
3324 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
3325 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3326 --raise a special kind of error to signal the caller
3327 RAISE STORAGE_ERROR;
3328 END;
3329
3330 -- Public
3331 PROCEDURE COMPILE_CONFIG_INSTANCE(x_run_id OUT NOCOPY NUMBER)
3332 IS
3333 l_ctxt VARCHAR2(60) := PKG_NAME||'COMPILE_CONFIG_INSTANCE';
3334
3335 l_config_instance_id NUMBER;
3336 BEGIN
3337 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
3338
3339 --get the config_instance_id, throws error if not initialized
3340 l_config_instance_id := FND_OAM_DSCFG_INSTANCES_PKG.GET_CURRENT_ID;
3341 fnd_oam_debug.log(1, l_ctxt, 'Using config instance id: '||l_config_instance_id);
3342
3343 --clear the package state data
3344 fnd_oam_debug.log(1, l_ctxt, 'Resetting package state variables');
3345 b_objects.DELETE;
3346 b_dml_update_segments.DELETE;
3347 b_dml_delete_stmts.DELETE;
3348 b_dml_truncate_stmts.DELETE;
3349 b_primary_domains.DELETE;
3350 b_domain_metadata_map.DELETE;
3351 b_dependency_groups.DELETE;
3352 b_domain_to_group_map.DELETE;
3353 b_run.object_id := NULL;
3354 b_bundles.DELETE;
3355
3356 --bulk fetch the objects from the database and fill the state
3357 fnd_oam_debug.log(1, l_ctxt, 'Fetching Compilable Objects');
3358 FETCH_COMPILABLE_OBJECTS(l_config_instance_id);
3359
3360 --now that all the objects have been fetched and cached, traverse the caches
3361 --and figure out which primary domains are related to one another and group them into
3362 --dependency groups
3363 fnd_oam_debug.log(1, l_ctxt, 'Computing Dependency Groups');
3364 COMPUTE_DEPENDENCY_GROUPS;
3365
3366 --ALL of the data should be parsed into groups and validated by this point.
3367
3368 --dump out the engine entities, if any fail, skip processing the rest since we don't
3369 --have a solid way to
3370 BEGIN
3371 fnd_oam_debug.log(1, l_ctxt, 'Generating an Engine Run Entity');
3372 GENERATE_ENGINE_RUN(l_config_instance_id);
3373
3374 --generate the engine bundles
3375 fnd_oam_debug.log(1, l_ctxt, 'Generating Engine Bundles');
3376 GENERATE_ENGINE_BUNDLES;
3377
3378 --traverse the dependency groups and output
3379 fnd_oam_debug.log(1, l_ctxt, 'Generating Engine Tasks');
3380 GENERATE_ENGINE_TASKS;
3381
3382 --write out the updated run and bundle weights
3383 UPDATE_RUN_BUNDLE_WEIGHTS;
3384 EXCEPTION
3385 WHEN PROGRAM_ERROR THEN
3386 -- a child function failed, it should have written a message somewhere.
3387 RAISE;
3388 WHEN OTHERS THEN
3389 --if we can write this error to the run, do so
3390 IF b_run.object_id IS NOT NULL THEN
3391 MARK_OBJECT_AS_ERRORED(b_run.object_id,
3392 l_ctxt,
3393 SQLCODE,
3394 SQLERRM);
3395 END IF;
3396 RAISE PROGRAM_ERROR;
3397 END;
3398
3399 --finally write out all dirty objects
3400 WRITE_DIRTY_OBJECTS;
3401
3402 --success
3403 x_run_id := b_run.run_id;
3404 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3405 EXCEPTION
3406 WHEN STORAGE_ERROR THEN
3407 -- only raised by write_dirty_objects to tell us it failed and we should skip trying to
3408 -- write the dirty objects again.
3409 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3410 RAISE;
3411 WHEN PROGRAM_ERROR THEN
3412 -- one of the child methods failed, try to write dirty objects out
3413 BEGIN
3414 WRITE_DIRTY_OBJECTS;
3415 EXCEPTION
3416 WHEN OTHERS THEN
3417 -- if we can't then there's nothing else we can do but raise the exception and hope
3418 -- there's something in the logs.
3419 null;
3420 END;
3421 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3422 RAISE;
3423 WHEN NO_DATA_FOUND THEN
3424 --just exit, this should only occur at the beginning before processing
3425 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3426 RAISE;
3427 WHEN OTHERS THEN
3428 -- this should only occur locally if something is really wrong, just raise it up
3429 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
3430 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3431 RAISE;
3432 END;
3433
3434 -- Public
3435 FUNCTION GET_DEFAULT_NUM_WORKERS
3436 RETURN NUMBER
3437 IS
3438 l_ctxt VARCHAR2(60) := PKG_NAME||'GET_DEFAULT_NUM_WORKERS';
3439 BEGIN
3440 fnd_oam_debug.log(2, l_ctxt, 'ENTER');
3441
3442 --make sure we've set the default_workers_allowed
3443 IF B_DEFAULT_WORKERS_ALLOWED IS NULL THEN
3444 BEGIN
3445 SELECT NVL(to_number(value), 1) - 1
3446 INTO B_DEFAULT_WORKERS_ALLOWED
3447 FROM v$system_parameter
3448 WHERE name = 'cpu_count';
3449
3450 IF B_DEFAULT_WORKERS_ALLOWED <= 0 THEN
3451 B_DEFAULT_WORKERS_ALLOWED := 1;
3452 END IF;
3453 EXCEPTION
3454 WHEN OTHERS THEN
3455 B_DEFAULT_WORKERS_ALLOWED := 1;
3456 END;
3457 END IF;
3458 fnd_oam_debug.log(1, l_ctxt, 'Default Workers Allowed: '||B_DEFAULT_WORKERS_ALLOWED);
3459
3460 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3461 RETURN B_DEFAULT_WORKERS_ALLOWED;
3462 EXCEPTION
3463 WHEN OTHERS THEN
3464 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
3465 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3466 RAISE;
3467 END;
3468
3469 -- Public
3470 FUNCTION GET_DEFAULT_BATCH_SIZE
3471 RETURN NUMBER
3472 IS
3473 l_ctxt VARCHAR2(60) := PKG_NAME||'GET_DEFAULT_BATCH_SIZE';
3474 BEGIN
3475 --currently static
3476 RETURN B_DEFAULT_BATCH_SIZE;
3477 EXCEPTION
3478 WHEN OTHERS THEN
3479 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
3480 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3481 RAISE;
3482 END;
3483
3484 -- Public
3485 FUNCTION GET_DFLT_VALID_CHECK_INTERVAL
3486 RETURN NUMBER
3487 IS
3488 l_ctxt VARCHAR2(60) := PKG_NAME||'GET_DFLT_VALID_CHECK_INTERVAL';
3489 BEGIN
3490 --currently static
3491 RETURN B_DEFAULT_VALID_CHECK_INTERVAL;
3492 EXCEPTION
3493 WHEN OTHERS THEN
3494 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
3495 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3496 RAISE;
3497 END;
3498
3499 -- Public
3500 FUNCTION GET_DFLT_MIN_PARALLEL_WEIGHT
3501 RETURN NUMBER
3502 IS
3503 l_ctxt VARCHAR2(60) := PKG_NAME||'GET_DFLT_MIN_PARALLEL_WEIGHT';
3504 BEGIN
3505 --currently static
3506 RETURN B_DEFAULT_MIN_PARALLEL_WEIGHT;
3507 EXCEPTION
3508 WHEN OTHERS THEN
3509 fnd_oam_debug.log(6, l_ctxt, 'Unexpected Error: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
3510 fnd_oam_debug.log(2, l_ctxt, 'EXIT');
3511 RAISE;
3512 END;
3513
3514 END FND_OAM_DSCFG_COMPILER_PKG;