[Home] [Help]
PACKAGE BODY: APPS.CZ_FCE_COMPILE
Source
1 PACKAGE BODY CZ_FCE_COMPILE AS
2 /* $Header: czfcecpb.pls 120.91.12010000.3 2009/01/08 17:51:55 asiaston ship $ */
3 ---------------------------------------------------------------------------------------
4 const_epoch_begin CONSTANT DATE := cz_utils.epoch_begin_;
5 const_epoch_end CONSTANT DATE := cz_utils.epoch_end_;
6 const_java_epoch_begin CONSTANT DATE := TO_DATE ('1970-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS');
7
8 const_file_signature CONSTANT RAW(4) := HEXTORAW ('00000000');
9
10 const_logicfile_def CONSTANT PLS_INTEGER := 1;
11 const_logicfile_port CONSTANT PLS_INTEGER := 2;
12 const_logicfile_constraint CONSTANT PLS_INTEGER := 3;
13
14 const_domainorder_minfirst CONSTANT PLS_INTEGER := 1;
15 const_domainorder_maxfirst CONSTANT PLS_INTEGER := 2;
16 const_domainorder_decmax CONSTANT PLS_INTEGER := 3;
17 const_domainorder_incmin CONSTANT PLS_INTEGER := 4;
18 const_domainorder_preffalse CONSTANT PLS_INTEGER := 5;
19 const_domainorder_preftrue CONSTANT PLS_INTEGER := 6;
20
21 const_max_localvariables CONSTANT PLS_INTEGER := 256;
22 const_max_registers CONSTANT PLS_INTEGER := 65536;
23
24 const_constantpool_maxsize CONSTANT PLS_INTEGER := 65536;
25 const_constantpool_buffersize CONSTANT PLS_INTEGER := 32768;
26
27 const_codememory_buffersize CONSTANT PLS_INTEGER := 32768;
28
29 const_min_double CONSTANT BINARY_DOUBLE := -1E+100D;
30 const_max_double CONSTANT BINARY_DOUBLE := 1E+100D;
31 const_max_instance_set CONSTANT PLS_INTEGER := 100;
32
33 const_context_generic CONSTANT PLS_INTEGER := 0;
34 const_context_target CONSTANT PLS_INTEGER := 1;
35 const_context_contributor CONSTANT PLS_INTEGER := 2;
36 const_context_literal CONSTANT PLS_INTEGER := 3;
37 const_context_accumulation CONSTANT PLS_INTEGER := 4;
38 const_context_logical CONSTANT PLS_INTEGER := 5;
39 const_context_forall CONSTANT PLS_INTEGER := 6;
40 const_context_compatible CONSTANT PLS_INTEGER := 7;
41 const_context_selection CONSTANT PLS_INTEGER := 8;
42 const_context_numeric CONSTANT PLS_INTEGER := 9;
43 const_context_constant CONSTANT PLS_INTEGER := 10;
44 const_context_heuristics CONSTANT PLS_INTEGER := 11;
45 const_context_aggregatesum CONSTANT PLS_INTEGER := 12;
46
47 const_no_instances CONSTANT PLS_INTEGER := 0;
48 const_quantifier_created CONSTANT PLS_INTEGER := 1;
49 const_resourcesum_required CONSTANT PLS_INTEGER := 2;
50
51 const_ruletype_compatible CONSTANT PLS_INTEGER := 0;
52 const_ruletype_forall CONSTANT PLS_INTEGER := 1;
53
54 const_valuetype_unknown CONSTANT PLS_INTEGER := -1;
55 const_valuetype_node CONSTANT PLS_INTEGER := 0;
56 const_valuetype_literal CONSTANT PLS_INTEGER := 1;
57 const_valuetype_variable CONSTANT PLS_INTEGER := 2;
58 const_valuetype_selection CONSTANT PLS_INTEGER := 3;
59 const_valuetype_sysprop CONSTANT PLS_INTEGER := 4;
60
61 const_textid_resultnotvalid CONSTANT PLS_INTEGER := 74;
62 const_mask_all_usages CONSTANT VARCHAR2(16) := '0000000000000000';
63 const_mask_no_usages CONSTANT VARCHAR2(16) := 'FFFFFFFFFFFFFFFF';
64
65 g_sw_msg_prefix VARCHAR2(4000) := NULL;
66 g_se_msg_prefix VARCHAR2(4000) := NULL;
67
68 /*------------------------------------------------------------------------------------
69 List of tags:
70 -------------
71 #<path in model def>
72 #<constant pool format>
73 #<problem>
74 #<dio integration>
75 #<optimization>
76 #<optimization-reverseport>
77 #<verification>
78 #<temporary>
79 #<should never happen>
80 #<important>
81 #<logic files handling>
82 #<todo>
83 -------------------------------------------------------------------------------------*/
84 --------------------------------------------------------------------------------------
85 /*------------------------------------------------------------------------------------
86 Hash keys for local variables:
87 ------------------------------
88 model defs: psnodeid
89 instance quantifiers: psnodeid1_psnodeid2_..._psnodeidN
90 any node except targets and contributors: psnodeid-explid
91
92 temporary local variables (never need to be re-generated): 'var', 'iq', 'exp'
93
94 Hash keys for registers:
95 ------------------------
96 instance quantifies in accumulator rules: psnodeid1_psnodeid2_..._psnodeidN
97 targets in accumulator rules: psnodeid:explid
98 contributors to a target: <number>$psnodeid:explid
99 generic assistant variables: _<assistant_var_id>
100 dedicated register for contributions: 'value'
101
102 Variable names:
103 ---------------
104 feature-property assistant variable: _psnodeid_propertyid
105 -------------------------------------------------------------------------------------*/
106 -- Function that is be used to get the message text for the not translated
107 -- system messages.
108 -- Note: It is temporarily used for new FCE user warnings and errors till they are
109 -- defined in FND_NEW_MESSAGES table.
110 FUNCTION GET_NOT_TRANSLATED_TEXT(inMessageName IN VARCHAR2,
111 inToken1 IN VARCHAR2 DEFAULT NULL, inValue1 IN VARCHAR2 DEFAULT NULL,
112 inToken2 IN VARCHAR2 DEFAULT NULL, inValue2 IN VARCHAR2 DEFAULT NULL,
113 inToken3 IN VARCHAR2 DEFAULT NULL, inValue3 IN VARCHAR2 DEFAULT NULL,
114 inToken4 IN VARCHAR2 DEFAULT NULL, inValue4 IN VARCHAR2 DEFAULT NULL,
115 inToken5 IN VARCHAR2 DEFAULT NULL, inValue5 IN VARCHAR2 DEFAULT NULL,
116 inToken6 IN VARCHAR2 DEFAULT NULL, inValue6 IN VARCHAR2 DEFAULT NULL) RETURN VARCHAR2 IS
117 v_String VARCHAR2(4000) := NULL;
118 BEGIN
119 IF inToken1 IS NULL THEN
120 RETURN inMessageName;
121 ELSE
122 v_String := replace(inMessageName, '^'||inToken1, inValue1);
123 IF inToken2 IS NULL THEN
124 RETURN v_String;
125 ELSE
126 v_String := replace(v_String, '^'||inToken2, inValue2);
127 IF inToken3 IS NULL THEN
128 RETURN v_String;
129 ELSE
130 v_String := replace(v_String, '^'||inToken3, inValue3);
131 IF inToken4 IS NULL THEN
132 RETURN v_String;
133 ELSE
134 v_String := replace(v_String, '^'||inToken4, inValue4);
135 IF inToken5 IS NULL THEN
136 RETURN v_String;
137 ELSE
138 v_String := replace(v_String, '^'||inToken5, inValue5);
139 IF inToken6 IS NULL THEN
140 RETURN v_String;
141 ELSE
142 v_String := replace(v_String, '^'||inToken5, inValue5);
143 END IF; --Token6
144 END IF; -- Token5
145 END IF; -- Token4
146 END IF; -- Token3
147 END IF; -- Token2
148 END IF; -- Token1
149 RETURN v_String;
150 END GET_NOT_TRANSLATED_TEXT;
151 -------------------------------------------------------------------------------------
152 -- Following three report_and_raise procedures log the message to cz_db_logs
153 -- and raise the appropriate exception
154
155 -- This procedure reports user warning and by default raises
156 -- CZ_LOGICGEN_WARNING exception. To stop raising exception
157 -- set the p_raise_exception flag to FALSE.
158 PROCEDURE report_and_raise_warning(
159 p_message IN VARCHAR2
160 , p_run_id IN NUMBER
161 , p_model_id IN NUMBER
162 , p_ps_node_id IN NUMBER DEFAULT NULL
163 , p_rule_id IN NUMBER DEFAULT NULL
164 , p_error_stack IN VARCHAR2 DEFAULT NULL
165 , p_raise_exception IN BOOLEAN DEFAULT TRUE ) IS
166 BEGIN
167 CZ_FCE_COMPILE_UTILS.REPORT_WARNING(
168 p_message => p_message,
169 p_run_id => p_run_id,
170 p_model_id => p_model_id,
171 p_ps_node_id => p_ps_node_id,
172 p_rule_id => p_rule_id,
173 p_error_stack => p_error_stack
174 );
175 IF p_raise_exception THEN
176 RAISE CZ_LOGICGEN_WARNING;
177 END IF;
178 END report_and_raise_warning;
179 -------------------------------------------------------------------------------------
180 -- This procedure reports user system warning and by default raises
181 -- CZ_LOGICGEN_WARNING exception. This procedure prefixes the
182 -- given message with generic system warning note. To stop raising exception
183 -- set the p_raise_exception flag to FALSE.
184 PROCEDURE report_and_raise_sys_warning(
185 p_message IN VARCHAR2
186 , p_run_id IN NUMBER
187 , p_model_id IN NUMBER
188 , p_ps_node_id IN NUMBER DEFAULT NULL
189 , p_rule_id IN NUMBER DEFAULT NULL
190 , p_error_stack IN VARCHAR2 DEFAULT NULL
191 , p_raise_exception IN BOOLEAN DEFAULT TRUE ) IS
192 BEGIN
193 IF g_sw_msg_prefix IS NULL THEN
194 -- System Warning: Generally caused by environment or system issues.
195 g_sw_msg_prefix := CZ_UTILS.GET_TEXT(CZ_FCE_SW_GENERIC_PREFIX);
196 END IF;
197 CZ_FCE_COMPILE_UTILS.REPORT_WARNING(
198 p_message => g_sw_msg_prefix || p_message,
199 p_run_id => p_run_id,
200 p_model_id => p_model_id,
201 p_ps_node_id => p_ps_node_id,
202 p_rule_id => p_rule_id,
203 p_error_stack => p_error_stack
204 );
205 IF p_raise_exception THEN
206 RAISE CZ_LOGICGEN_SYS_WARNING;
207 END IF;
208 END report_and_raise_sys_warning;
209 -------------------------------------------------------------------------------------
210 -- This procedure reports user error and by default raises
211 -- CZ_LOGICGEN_ERROR exception. To stop raising exception
212 -- set the p_raise_exception flag to FALSE.
213 PROCEDURE report_and_raise_error(
214 p_message IN VARCHAR2
215 , p_run_id IN NUMBER
216 , p_model_id IN NUMBER
217 , p_ps_node_id IN NUMBER DEFAULT NULL
218 , p_rule_id IN NUMBER DEFAULT NULL
219 , p_error_stack IN VARCHAR2 DEFAULT NULL
220 , p_raise_exception IN BOOLEAN DEFAULT TRUE ) IS
221 BEGIN
222 CZ_FCE_COMPILE_UTILS.REPORT_ERROR(
223 p_message => p_message,
224 p_run_id => p_run_id,
225 p_model_id => p_model_id,
226 p_ps_node_id => p_ps_node_id,
227 p_rule_id => p_rule_id,
228 p_error_stack => p_error_stack
229 );
230 IF p_raise_exception THEN
231 RAISE CZ_LOGICGEN_ERROR;
232 END IF;
233 END report_and_raise_error;
234 -------------------------------------------------------------------------------------
235 -- This procedure reports system error and by default raises
236 -- CZ_LOGICGEN_ERROR exception. This procedure prefixes the
237 -- given message with generic system error note. To stop raising exception
238 -- set the p_raise_exception flag to FALSE.
239 PROCEDURE report_and_raise_sys_error(
240 p_message IN VARCHAR2
241 , p_run_id IN NUMBER
242 , p_model_id IN NUMBER
243 , p_ps_node_id IN NUMBER DEFAULT NULL
244 , p_rule_id IN NUMBER DEFAULT NULL
245 , p_error_stack IN VARCHAR2 DEFAULT NULL
246 , p_raise_exception IN BOOLEAN DEFAULT TRUE ) IS
247 BEGIN
248 IF g_se_msg_prefix IS NULL THEN
249 -- System Error: Generally caused by environment or system issues.
250 g_se_msg_prefix := CZ_UTILS.GET_TEXT(CZ_FCE_SE_GENERIC_PREFIX);
251 END IF;
252 CZ_FCE_COMPILE_UTILS.REPORT_SYSTEM_ERROR(
253 p_message => g_se_msg_prefix || p_message,
254 p_run_id => p_run_id,
255 p_model_id => p_model_id,
256 p_ps_node_id => p_ps_node_id,
257 p_rule_id => p_rule_id,
258 p_error_stack => p_error_stack
259 );
260 IF p_raise_exception THEN
261 RAISE CZ_LOGICGEN_SYS_ERROR;
262 END IF;
263 END report_and_raise_sys_error;
264 -------------------------------------------------------------------------------------
265 --This procedure compiles logic for a model specified by either a database id
266 --
267 --p_object_id: Database model id. Used when the second parameter is null.
268 --x_run_id: Unique id of the compilation session.
269 --p_two_phase_commit: 0 - compiler commits the logic, 1 - no commit.
270 --p_debug_mode: 0 - normal mode, 1 - debug mode.
271
272 PROCEDURE compile_logic_ ( p_object_id IN NUMBER
273 , x_run_id IN OUT NOCOPY NUMBER
274 , p_two_phase_commit IN PLS_INTEGER
275 , p_debug_mode IN PLS_INTEGER
276 ) IS
277
278 v_index PLS_INTEGER;
279
280 h_psnid_psnodetype type_node_hashtable;
281 h_psnid_detailedtype type_node_hashtable;
282 h_psnid_decimalqtyflag type_flag_hashtable;
283 h_psnid_persistentnodeid type_node_hashtable;
284 h_psnid_devlprojectid type_node_hashtable;
285 h_psnid_parentid type_node_hashtable;
286 h_psnid_name type_name_hashtable;
287
288 h_devlid_modelvisited type_data_hashtable;
289 h_psnid_createreverseport type_data_hashtable;
290 h_psnid_numberofchildren type_data_hashtable;
291 h_psnid_lastchildindex type_data_hashtable;
292 h_psnid_backindex type_data_hashtable;
293 h_psnid_propid_isvalid type_bool_hashtable;
294
295 t_psn_psnodeid type_number_table;
296 t_psn_parentid type_number_table;
297 t_psn_itemid type_number_table;
298 t_psn_minimum type_number_table;
299 t_psn_maximum type_number_table;
300 t_psn_name type_varchar4000_table;
301 t_psn_intltextid type_number_table;
302 t_psn_minimumselected type_number_table;
303 t_psn_maximumselected type_number_table;
304 t_psn_psnodetype type_number_table;
305 t_psn_initialvalue type_varchar4000_table;
306 t_psn_virtualflag type_varchar1_table;
307 t_psn_featuretype type_number_table;
308 t_psn_bomrequiredflag type_varchar1_table;
309 t_psn_referenceid type_number_table;
310 t_psn_persistentnodeid type_number_table;
311 t_psn_effectivefrom type_date_table;
312 t_psn_effectiveuntil type_date_table;
313 t_psn_effectiveusagemask type_varchar16_table;
314 t_psn_effectivitysetid type_number_table;
315 t_psn_decimalqtyflag type_varchar1_table;
316 t_psn_ibtrackable type_varchar1_table;
317 t_psn_accumulatorflag type_varchar1_table;
318 t_psn_initialnumvalue type_number_table;
319 t_psn_instantiableflag type_varchar1_table;
320 t_psn_shippableitemflag type_varchar1_table;
321 t_psn_invtransactflag type_varchar1_table;
322 t_psn_atoflag type_varchar1_table;
323 t_psn_serialitemflag type_varchar1_table;
324 t_psn_countedoptionsflag type_varchar1_table;
325 t_psn_devlprojectid type_number_table;
326 t_psn_domainorder type_number_table;
327 t_psn_reverseportid type_number_table;
328 t_psn_maxqtyperoption type_number_table;
329 t_psn_detailedtype type_number_table;
330
331 h_explid_referencepath type_numbertable_hashtable;
332 h_psnid_modelpath type_numbertable_hashtable;
333 h_psnid_explid_completepath type_numbertable_hashtable;
334
335 t_effset_effectivitysetid type_number_table;
336 t_effset_effectivefrom type_date_table;
337 t_effset_effectiveuntil type_date_table;
338
339 h_effsetid_effectivefrom type_date_hashtable;
340 h_effsetid_effectiveuntil type_date_hashtable;
341 ---------------------------------------------------------------------------------------
342 -- Scope: compile_logic_
343 PROCEDURE debug ( p_message IN VARCHAR2 ) IS
344 BEGIN
345
346 IF ( p_debug_mode = 1 ) THEN
347
348 CZ_FCE_COMPILE_UTILS.REPORT_INFO(
349 p_message => p_message,
350 p_run_id => - x_run_id,
351 p_model_id => null,
352 p_ps_node_id => null,
353 p_rule_id => null,
354 p_error_stack => null
355 );
356 END IF;
357 END debug;
358 ---------------------------------------------------------------------------------------
359 FUNCTION build_model_path ( p_node_id IN NUMBER ) RETURN type_number_table IS
360
361 l_node NUMBER;
362 l_key VARCHAR2(4000) := TO_CHAR ( p_node_id );
363 tl_id_path type_number_table;
364
365 BEGIN
366
367 IF ( h_psnid_modelpath.EXISTS ( l_key )) THEN RETURN h_psnid_modelpath ( l_key ); END IF;
368
369 --When participant is a Bom Reference, we need to switch to the referenced Bom Model and
370 --have it in the path. This way generate_path correctly generate instance quantifier for
371 --the referring reference.
372
373 IF ( h_psnid_psnodetype ( l_key ) = h_psntypes ('bommodel')) THEN
374
375 tl_id_path ( 1 ) := p_node_id;
376
377 END IF;
378
379 l_node := p_node_id;
380
381 WHILE ( h_psnid_parentid ( TO_CHAR ( l_node )) IS NOT NULL ) LOOP
382
383 tl_id_path ( tl_id_path.COUNT + 1 ) := l_node;
384 l_node := h_psnid_parentid ( TO_CHAR ( l_node ));
385
386 END LOOP;
387
388 h_psnid_modelpath ( l_key ) := tl_id_path;
389
390 RETURN tl_id_path;
391
392 EXCEPTION
393 WHEN OTHERS THEN
394
395 tl_id_path.DELETE;
396 RETURN tl_id_path;
397
398 END build_model_path;
399 ----------------------------------------------------------------------------------
400 FUNCTION ps_node_id_table_to_string ( p_node_id_table type_number_table ) RETURN VARCHAR2 IS
401
402 l_path VARCHAR2(4000) := NULL;
403
404 BEGIN
405
406 IF ( p_node_id_table IS NULL OR p_node_id_table.COUNT = 0 ) THEN
407
408 RETURN NULL;
409
410 ELSE
411
412 FOR iNode IN REVERSE 1 .. p_node_id_table.COUNT LOOP
413
414 IF ( iNode = p_node_id_table.COUNT ) THEN
415
416 l_path := l_path || h_psnid_name ( p_node_id_table ( iNode ));
417
418 ELSE
419
420 l_path := l_path || '.' || h_psnid_name ( p_node_id_table ( iNode ));
421
422 END IF;
423 END LOOP;
424
425 RETURN l_path;
426
427 END IF;
428 EXCEPTION
429 WHEN OTHERS THEN
430
431 RETURN NULL;
432
433 END ps_node_id_table_to_string;
434 ---------------------------------------------------------------------------------------
435 PROCEDURE read_model_data ( p_component_id IN NUMBER ) IS
436
437 l_psn_psnodeid type_number_table;
438 l_psn_parentid type_number_table;
439 l_psn_itemid type_number_table;
440 l_psn_minimum type_number_table;
441 l_psn_maximum type_number_table;
442 l_psn_name type_varchar4000_table;
443 l_psn_intltextid type_number_table;
444 l_psn_minimumselected type_number_table;
445 l_psn_maximumselected type_number_table;
446 l_psn_psnodetype type_number_table;
447 l_psn_initialvalue type_varchar4000_table;
448 l_psn_virtualflag type_varchar1_table;
449 l_psn_featuretype type_number_table;
450 l_psn_bomrequiredflag type_varchar1_table;
451 l_psn_referenceid type_number_table;
452 l_psn_persistentnodeid type_number_table;
453 l_psn_effectivefrom type_date_table;
454 l_psn_effectiveuntil type_date_table;
455 l_psn_effectiveusagemask type_varchar16_table;
456 l_psn_effectivitysetid type_number_table;
457 l_psn_decimalqtyflag type_varchar1_table;
458 l_psn_ibtrackable type_varchar1_table;
459 l_psn_accumulatorflag type_varchar1_table;
460 l_psn_initialnumvalue type_number_table;
461 l_psn_instantiableflag type_varchar1_table;
462 l_psn_shippableitemflag type_varchar1_table;
463 l_psn_invtransactflag type_varchar1_table;
464 l_psn_atoflag type_varchar1_table;
465 l_psn_serialitemflag type_varchar1_table;
466 l_psn_countedoptionsflag type_varchar1_table;
467 l_psn_devlprojectid type_number_table;
468 l_psn_domainorder type_number_table;
469 l_psn_reverseportid type_number_table;
470 l_psn_maxqtyperoption type_number_table;
471 l_psn_detailedtype type_number_table;
472
473 l_port_table type_integer_table;
474 l_reverseport_table type_integer_table;
475 l_index PLS_INTEGER;
476 l_parent_id VARCHAR2(4000);
477 l_node_id VARCHAR2(4000);
478
479 l_model_id NUMBER;
480 ----------------------------------------------------------------------------------
481 PROCEDURE set_token ( p_mark IN VARCHAR2 ) IS
482 BEGIN
483
484 t_psn_psnodetype ( v_index ) := h_psntypes ( p_mark );
485 t_psn_psnodeid ( v_index ) := p_component_id;
486 t_psn_devlprojectid ( v_index ) := p_component_id;
487 t_psn_parentid ( v_index ) := NULL;
488
489 v_index := v_index + 1;
490
491 END set_token;
492 ----------------------------------------------------------------------------------
493 BEGIN --> read_model_data
494
495 --This procedure reads model hierarchy structure in a certain format that is used by
496 --compile_logic_file procedure. The format uses tokens - dummy nodes of special type
497 --that are embedded into the structure (see the above procedure set_token for the
498 --columns that are used in the definition). The resulting memory structure looks
499 --like this:
500
501 --'beginstructure'
502 -- <model_data>
503 -- 'beginstructure'
504 -- <child_model_data>
505 -- ...
506 -- 'beginport'
507 -- <child_model_ports>
508 -- 'endport'
509 -- 'endstructure'
510 -- ...
511 -- 'beginport'
512 -- <model_ports>
513 -- 'endport'
514 -- 'beginrule'
515 -- <reverse_ports>
516 -- 'endrule'
517 --'endstructure'
518
519 --Each model data is contained only once in this hierarchy, when the model is first referenced.
520 --The port section of the referencing model cannot be processed before the referenced model is
521 --processed.
522
523 h_devlid_modelvisited ( TO_CHAR (p_component_id)) := 1;
524
525 SELECT ps_node_id, parent_id, item_id, minimum, maximum, name, intl_text_id, minimum_selected,
526 maximum_selected, ps_node_type, initial_value, virtual_flag, feature_type, bom_required_flag,
527 reference_id, persistent_node_id, effective_from, effective_until, effective_usage_mask,
528 effectivity_set_id, decimal_qty_flag, ib_trackable, accumulator_flag, initial_num_value,
529 instantiable_flag, shippable_item_flag, inventory_transactable_flag, assemble_to_order_flag,
530 serializable_item_flag, counted_options_flag, devl_project_id, domain_order,
531 reverse_connector_id, max_qty_per_option
532 BULK COLLECT INTO
533 l_psn_psnodeid, l_psn_parentid, l_psn_itemid, l_psn_minimum, l_psn_maximum, l_psn_name,
534 l_psn_intltextid, l_psn_minimumselected, l_psn_maximumselected, l_psn_psnodetype,
535 l_psn_initialvalue, l_psn_virtualflag, l_psn_featuretype, l_psn_bomrequiredflag,
536 l_psn_referenceid, l_psn_persistentnodeid, l_psn_effectivefrom, l_psn_effectiveuntil,
537 l_psn_effectiveusagemask, l_psn_effectivitysetid, l_psn_decimalqtyflag, l_psn_ibtrackable,
538 l_psn_accumulatorflag, l_psn_initialnumvalue, l_psn_instantiableflag, l_psn_shippableitemflag,
539 l_psn_invtransactflag, l_psn_atoflag, l_psn_serialitemflag, l_psn_countedoptionsflag,
540 l_psn_devlprojectid, l_psn_domainorder, l_psn_reverseportid, l_psn_maxqtyperoption
541 FROM cz_ps_nodes
542 WHERE deleted_flag = '0'
543 START WITH ps_node_id = p_component_id
544 CONNECT BY PRIOR deleted_flag = '0' AND PRIOR ps_node_id = parent_id;
545
546 --Note: the condition on PRIOR deleted_flag is included to handle the cases when children of a deleted
547 --parent are not deleted, for example when options of a deleted option feature still have the value of
548 --deleted_flag = '0'. If such situation is not possible, the condition can be removed if it slows down
549 --the query.
550
551 IF (l_psn_psnodeid.COUNT > 0) THEN
552
553 set_token ('beginstructure');
554
555 FOR i IN 1..l_psn_psnodeid.COUNT LOOP
556
557 l_psn_virtualflag ( i ) := NVL ( l_psn_virtualflag ( i ), '1' );
558 l_psn_instantiableflag ( i ) := NVL ( l_psn_instantiableflag ( i ), h_instantiability ('mandatory'));
559 l_psn_detailedtype ( i ) := l_psn_psnodetype ( i );
560
561 --#<important>
562 --If splitting the detailed type further, it is necessary to find all existing references
563 --to this detailed type in the code to see if they need to be modified.
564
565 IF ( l_psn_psnodetype ( i ) = h_psntypes ('feature')) THEN
566
567 l_psn_detailedtype ( i ) := l_psn_featuretype ( i );
568
569 ELSIF ( l_psn_psnodetype ( i ) = h_psntypes ('component')) THEN
570
571 IF ( l_psn_parentid ( i ) IS NULL ) THEN
572
573 l_psn_detailedtype ( i ) := h_psntypes ('root');
574
575 ELSIF ( l_psn_virtualflag ( i ) = '1' ) THEN
576
577 l_psn_detailedtype ( i ) := h_psntypes ('singleton');
578
579 END IF;
580 END IF;
581
582 t_psn_psnodeid ( v_index ) := l_psn_psnodeid ( i );
583 t_psn_parentid ( v_index ) := l_psn_parentid ( i );
584 t_psn_itemid ( v_index ) := l_psn_itemid ( i );
585 t_psn_minimum ( v_index ) := l_psn_minimum ( i );
586 t_psn_maximum ( v_index ) := l_psn_maximum ( i );
587 t_psn_name ( v_index ) := l_psn_name ( i );
588 t_psn_intltextid ( v_index ) := l_psn_intltextid ( i );
589 t_psn_minimumselected ( v_index ) := l_psn_minimumselected ( i );
590 t_psn_maximumselected ( v_index ) := l_psn_maximumselected ( i );
591 t_psn_psnodetype ( v_index ) := l_psn_psnodetype ( i );
592 t_psn_initialvalue ( v_index ) := l_psn_initialvalue ( i );
593 t_psn_virtualflag ( v_index ) := l_psn_virtualflag ( i );
594 t_psn_featuretype ( v_index ) := l_psn_featuretype ( i );
595 t_psn_bomrequiredflag ( v_index ) := l_psn_bomrequiredflag ( i );
596 t_psn_referenceid ( v_index ) := l_psn_referenceid ( i );
597 t_psn_persistentnodeid ( v_index ) := l_psn_persistentnodeid ( i );
598 t_psn_effectivefrom ( v_index ) := l_psn_effectivefrom ( i );
599 t_psn_effectiveuntil ( v_index ) := l_psn_effectiveuntil ( i );
600 t_psn_effectiveusagemask ( v_index ) := l_psn_effectiveusagemask ( i );
601 t_psn_effectivitysetid ( v_index ) := l_psn_effectivitysetid ( i );
602 t_psn_decimalqtyflag ( v_index ) := l_psn_decimalqtyflag ( i );
603 t_psn_ibtrackable ( v_index ) := l_psn_ibtrackable ( i );
604 t_psn_accumulatorflag ( v_index ) := l_psn_accumulatorflag ( i );
605 t_psn_initialnumvalue ( v_index ) := l_psn_initialnumvalue ( i );
606 t_psn_instantiableflag ( v_index ) := l_psn_instantiableflag ( i );
607 t_psn_shippableitemflag ( v_index ) := l_psn_shippableitemflag ( i );
608 t_psn_invtransactflag ( v_index ) := l_psn_invtransactflag ( i );
609 t_psn_atoflag ( v_index ) := l_psn_atoflag ( i );
610 t_psn_serialitemflag ( v_index ) := l_psn_serialitemflag ( i );
611 t_psn_countedoptionsflag ( v_index ) := l_psn_countedoptionsflag ( i );
612 t_psn_devlprojectid ( v_index ) := l_psn_devlprojectid ( i );
613 t_psn_domainorder ( v_index ) := l_psn_domainorder ( i );
614 t_psn_reverseportid ( v_index ) := l_psn_reverseportid ( i );
615 t_psn_maxqtyperoption ( v_index ) := l_psn_maxqtyperoption ( i );
616 t_psn_detailedtype ( v_index ) := l_psn_detailedtype ( i );
617
618 l_node_id := TO_CHAR ( l_psn_psnodeid ( i ));
619
620 h_psnid_backindex ( l_node_id ) := v_index;
621 h_psnid_numberofchildren ( l_node_id ) := 0;
622
623 --If node is assigned to an effectivity set, its effectivities should be taken from this set.
624
625 IF ( l_psn_effectivitysetid ( i ) IS NOT NULL ) THEN
626 IF ( NOT h_effsetid_effectivefrom.EXISTS ( TO_CHAR ( l_psn_effectivitysetid ( i )))) THEN
627
628 report_and_raise_warning (
629 p_message => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SW_NODEINCORRECTEFFSET,
630 'NODE_NAME',
631 CZ_FCE_COMPILE_UTILS.GET_NODE_PATH ( l_psn_psnodeid ( i ),
632 ps_node_id_table_to_string (
633 build_model_path ( l_psn_psnodeid ( i )))),
634 'MODEL_NAME',
635 CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH ( p_component_id, null )),
636 p_run_id => x_run_id,
637 p_model_id => p_component_id,
638 p_raise_exception => FALSE
639 );
640
641 ELSE
642
643 t_psn_effectivefrom ( v_index ) := h_effsetid_effectivefrom ( TO_CHAR ( l_psn_effectivitysetid ( i )));
644 t_psn_effectiveuntil ( v_index ) := h_effsetid_effectiveuntil ( TO_CHAR ( l_psn_effectivitysetid ( i )));
645
646 END IF;
647 END IF;
648
649 --This is a global variable, it is used to index the whole hierarchy, in particular,
650 --it needs to be increased -before- following the references. So, caution should be
651 --exercised when moving this statement.
652
653 v_index := v_index + 1;
654
655 h_psnid_psnodetype ( l_node_id ) := l_psn_psnodetype ( i );
656 h_psnid_detailedtype ( l_node_id ) := l_psn_detailedtype ( i );
657 h_psnid_decimalqtyflag ( l_node_id ) := l_psn_decimalqtyflag ( i );
658 h_psnid_persistentnodeid ( l_node_id ) := l_psn_persistentnodeid ( i );
659 h_psnid_devlprojectid( l_node_id ) := l_psn_devlprojectid ( i );
660
661 --#<path in model def>
662 --This two arrays are introduced to be able to generate a full model path to be used when
663 --creating model defs. Currently this is used only for debugging purposes. For example in
664 --the following situation:
665 --
666 --M
667 --|_C1
668 --| |_C3
669 --|_C2
670 -- |_C3
671 --
672 --C3 can be different node with the same name. When creating XML from byte-code it will be
673 --not clear which model def for C3 belongs under which component.
674
675 h_psnid_name( l_node_id ) := l_psn_name ( i );
676 h_psnid_parentid( l_node_id ) := l_psn_parentid ( i );
677
678 --We have to do this here and not earlier as we may need the hash tables above to build to
679 --construct the path in the model.
680
681 IF ( l_psn_psnodetype ( i ) = h_psntypes ('connector')) THEN
682 -- Node ^NODE_NAME in Model ^MODEL_NAME is a Connector. In this release, Connectors are only supported in Orginal Configuration Engine type models.
683 report_and_raise_error (
684 p_message => CZ_UTILS.GET_TEXT ( CZ_FCE_E_CONNECTNOTSUPPORTED,
685 'NODE_NAME',
686 CZ_FCE_COMPILE_UTILS.GET_NODE_PATH ( l_psn_psnodeid ( i ),
687 ps_node_id_table_to_string(
688 build_model_path(l_psn_psnodeid ( i )) )
689 ),
690 'MODEL_NAME',
691 CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH ( p_component_id )),
692 p_run_id => x_run_id,
693 p_model_id => p_component_id
694 );
695 END IF;
696
697 IF ( l_psn_psnodetype(i) IN ( h_psntypes ('reference'), h_psntypes ('connector')) OR
698 ( l_psn_psnodetype(i) = h_psntypes('component') AND l_psn_parentid ( i ) IS NOT NULL)) THEN
699
700 --References, connectors and all non-root component variables go to the port file.
701
702 l_port_table ( l_port_table.COUNT + 1 ) := i;
703
704 --Now handle additional control tables for reverse ports. It is important to do it here before
705 --following the reference. The reason is that although Solver does not care on which of the
706 --reverse ports we call the setReversePort method, from the DIO integration point of view we
707 --need to call it on the 'parent' port.
708
709 IF ( l_psn_reverseportid ( i ) IS NOT NULL AND ( NOT h_psnid_createreverseport.EXISTS ( TO_CHAR ( l_psn_reverseportid ( i ))))) THEN
710
711 --This port has a reverse port defined, so we need to call setReversePort either on this
712 --port, or on the other port. If the other port has not been added to the rule section,
713 --add this one and remember it.
714
715 l_reverseport_table ( l_reverseport_table.COUNT + 1 ) := i;
716 h_psnid_createreverseport ( TO_CHAR ( l_psn_psnodeid ( i ))) := 1;
717
718 IF ( NOT h_psnid_devlprojectid.EXISTS ( TO_CHAR ( l_psn_reverseportid ( i )))) THEN
719
720 --The model containing the referring port has not been processed, we need to process this model
721 --to make sure that its logic exists, otherwise there will be a hash miss in emit_reverseport,
722 --and DIO won't be able to get the model def.
723
724 BEGIN
725
726 SELECT devl_project_id INTO l_model_id
727 FROM cz_ps_nodes
728 WHERE deleted_flag = '0'
729 AND ps_node_id = l_psn_reverseportid ( i );
730
731 EXCEPTION
732 WHEN OTHERS THEN
733
734 --#<should never happen>
735 report_and_raise_error (
736 p_message => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SE_REVCONNMODELNOTFOUND,
737 'MODEL_NAME',
738 CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH ( l_psn_reverseportid ( i ))),
739 p_run_id => x_run_id,
740 p_model_id => l_psn_reverseportid ( i )
741 );
742
743 END;
744
745 read_model_data ( l_model_id );
746
747 END IF;
748 END IF;
749
750 IF ( l_psn_referenceid ( i ) IS NOT NULL AND ( NOT h_devlid_modelvisited.EXISTS ( TO_CHAR ( l_psn_referenceid ( i ))))) THEN
751
752 read_model_data ( l_psn_referenceid ( i ));
753
754 END IF;
755 END IF;
756
757 IF ( l_psn_parentid ( i ) IS NOT NULL ) THEN
758
759 --Calculate number of children for each parent. May be useful for setting fields like maximum_selected.
760
761 l_parent_id := TO_CHAR ( l_psn_parentid ( i ));
762 h_psnid_numberofchildren ( l_parent_id ) := h_psnid_numberofchildren ( l_parent_id ) + 1;
763
764 --This table is useful when we need to collect all children of a parent across the whole
765 --structure.
766
767 h_psnid_lastchildindex ( l_parent_id ) := h_psnid_backindex ( l_node_id );
768
769 END IF;
770 END LOOP;
771
772 --After the model structure is read we append a 'port' section at the end containing all the
773 --references and connectors in the structure, for which port variables will be created. The
774 --section is enclosed in 'beginport'/'endport' tokens and contains only the values that are
775 --required for creating port variables - this determined what arrays we populate below. For
776 --example, initial_value is not used for port variables, and we don't populate the array.
777
778 --Components with defined reverse port are also here (one from each pair, another one is in
779 --the def file).
780
781 --This section is REQUIRED even if it is empty - we always create all files of all possible
782 --types as a solution to the problem described in #<logic files handling>.
783
784 set_token ('beginport');
785
786 FOR i IN 1..l_port_table.COUNT LOOP
787
788 l_index := l_port_table ( i );
789
790 t_psn_psnodeid ( v_index ) := l_psn_psnodeid ( l_index );
791 t_psn_persistentnodeid ( v_index ) := l_psn_persistentnodeid ( l_index );
792 t_psn_parentid ( v_index ) := l_psn_parentid ( l_index );
793 t_psn_psnodetype ( v_index ) := l_psn_psnodetype ( l_index );
794 t_psn_referenceid ( v_index ) := l_psn_referenceid ( l_index );
795 t_psn_reverseportid ( v_index ) := l_psn_reverseportid ( l_index );
796 t_psn_devlprojectid ( v_index ) := l_psn_devlprojectid ( l_index );
797 t_psn_name ( v_index ) := l_psn_name ( l_index );
798 t_psn_minimum ( v_index ) := l_psn_minimum ( l_index );
799 t_psn_maximum ( v_index ) := l_psn_maximum ( l_index );
800 t_psn_virtualflag ( v_index ) := l_psn_virtualflag ( l_index );
801 t_psn_instantiableflag ( v_index ) := l_psn_instantiableflag ( l_index );
802 t_psn_bomrequiredflag ( v_index ) := l_psn_bomrequiredflag ( l_index );
803 t_psn_minimumselected( v_index ) := l_psn_minimumselected( l_index );
804 t_psn_maximumselected( v_index ) := l_psn_maximumselected( l_index );
805 t_psn_initialnumvalue( v_index ) := l_psn_initialnumvalue( l_index );
806 t_psn_effectivefrom( v_index ) := l_psn_effectivefrom( l_index );
807 t_psn_effectiveuntil( v_index ) := l_psn_effectiveuntil( l_index );
808 t_psn_effectiveusagemask( v_index ) := l_psn_effectiveusagemask( l_index );
809 t_psn_detailedtype ( v_index ) := l_psn_detailedtype ( l_index );
810
811 v_index := v_index + 1;
812
813 END LOOP;
814
815 set_token ('endport');
816
817 --Now append the 'rule' section which contains all ports on which we need to call setReversePort.
818 --For each of them, the call will be generated in the rule logic file. Note, that this section is
819 --REQUIRED even if there is no reverse ports and it is empty.
820
821 set_token ('beginrule');
822
823 FOR i IN 1..l_reverseport_table.COUNT LOOP
824
825 l_index := l_reverseport_table ( i );
826
827 t_psn_psnodeid ( v_index ) := l_psn_psnodeid ( l_index );
828 t_psn_persistentnodeid ( v_index ) := l_psn_persistentnodeid ( l_index );
829 t_psn_reverseportid ( v_index ) := l_psn_reverseportid ( l_index );
830 t_psn_psnodetype ( v_index ) := l_psn_psnodetype ( l_index );
831
832 v_index := v_index + 1;
833
834 END LOOP;
835
836 set_token ('endrule');
837 set_token ('endstructure');
838
839 END IF; --> l_psn_psnodeid.COUNT > 0
840 END read_model_data;
841 ---------------------------------------------------------------------------------------
842 -- Scope: compile_logic_
843 PROCEDURE compile_logic_file ( p_component_id IN NUMBER
844 , p_type IN PLS_INTEGER
845 , p_model_path IN VARCHAR2 DEFAULT NULL
846 ) IS
847
848 h_StringConstantHash type_data_hashtable;
849 h_IntegerConstantHash type_data_hashtable;
850 h_LongConstantHash type_data_hashtable;
851 h_MaskConstantHash type_data_hashtable;
852 h_DoubleConstantHash type_data_hashtable;
853 h_MethodDescriptorHash type_integer_table;
854
855 h_LocalVariableHash type_data_hashtable;
856 h_LocalVariableBackPtr type_varchar4000_table;
857 h_RegisterHash type_data_hashtable;
858
859 l_var_min NUMBER;
860 l_var_max NUMBER;
861 l_var_count NUMBER;
862 l_option_count PLS_INTEGER;
863 l_feature_idx PLS_INTEGER;
864 l_reverseportcount PLS_INTEGER;
865
866 l_begin_date DATE;
867 l_end_date DATE;
868 l_model_path VARCHAR2(4000);
869 ---------------------------------------------------------------------------------------
870 -------------------------- LOGIC FILE IMPLEMENTATION ----------------------------------
871 ---------------------------------------------------------------------------------------
872 pool_ptr PLS_INTEGER;
873 code_ptr PLS_INTEGER;
874 localvariable_ptr PLS_INTEGER;
875 register_ptr PLS_INTEGER;
876
877 this_segment_nbr NUMBER;
878 this_file_id NUMBER;
879
880 segment_nbr_svp PLS_INTEGER;
881 code_ptr_svp PLS_INTEGER;
882 pool_ptr_svp PLS_INTEGER;
883
884 h_StringConstantHash_svp type_data_hashtable;
885 h_IntegerConstantHash_svp type_data_hashtable;
886 h_LongConstantHash_svp type_data_hashtable;
887 h_MaskConstantHash_svp type_data_hashtable;
888 h_DoubleConstantHash_svp type_data_hashtable;
889 h_MethodDescriptorHash_svp type_integer_table;
890
891 h_LocalVariableHash_svp type_data_hashtable;
892 h_RegisterHash_svp type_data_hashtable;
893
894 ConstantPool BLOB;
895 CodeMemory BLOB;
896
897 CodeMemory_buffer VARCHAR2(32767 BYTE);
898 code_buffer_ptr PLS_INTEGER;
899
900 ConstantPool_buffer VARCHAR2(32767 BYTE);
901 pool_buffer_ptr PLS_INTEGER;
902 ---------------------------------------------------------------------------------------
903 -- Scope: compile_logic_file
904 PROCEDURE flush_constant_pool IS
905
906 l_raw RAW(32767) := HEXTORAW ( ConstantPool_buffer );
907 l_len BINARY_INTEGER := UTL_RAW.LENGTH ( l_raw );
908
909 BEGIN
910
911 IF ( l_len > 0 ) THEN
912
913 DBMS_LOB.WRITEAPPEND ( ConstantPool, l_len, l_raw );
914
915 END IF;
916 END flush_constant_pool;
917 ---------------------------------------------------------------------------------------
918 -- Scope: compile_logic_file
919 PROCEDURE flush_code_memory IS
920
921 l_raw RAW(32767) := HEXTORAW ( CodeMemory_buffer );
922 l_len BINARY_INTEGER := UTL_RAW.LENGTH ( l_raw );
923
924 BEGIN
925
926 IF ( l_len > 0 ) THEN
927
928 DBMS_LOB.WRITEAPPEND ( CodeMemory, l_len, l_raw );
929
930 END IF;
931 END flush_code_memory;
932 ---------------------------------------------------------------------------------------
933 -- Scope: compile_logic_file
934 PROCEDURE init_logic_file IS
935 BEGIN
936
937 DBMS_LOB.CREATETEMPORARY ( ConstantPool, TRUE );
938 DBMS_LOB.CREATETEMPORARY ( CodeMemory, TRUE );
939
940 CodeMemory_buffer := NULL;
941 code_buffer_ptr := 0;
942
943 ConstantPool_buffer := NULL;
944 pool_buffer_ptr := 0;
945
946 pool_ptr := 0;
947 code_ptr := 0;
948 this_segment_nbr := 1;
949
950 localvariable_ptr := 0;
951 register_ptr := 0;
952
953 END init_logic_file;
954 ---------------------------------------------------------------------------------------
955 -- Scope: compile_logic_file
956 PROCEDURE next_logic_segment IS
957 BEGIN
958
959 DBMS_LOB.TRIM ( ConstantPool, 0 );
960 DBMS_LOB.TRIM ( CodeMemory, 0 );
961
962 CodeMemory_buffer := NULL;
963 code_buffer_ptr := 0;
964
965 ConstantPool_buffer := NULL;
966 pool_buffer_ptr := 0;
967
968 pool_ptr := 0;
969 code_ptr := 0;
970 this_segment_nbr := this_segment_nbr + 1;
971
972 h_StringConstantHash.DELETE;
973 h_IntegerConstantHash.DELETE;
974 h_LongConstantHash.DELETE;
975 h_MaskConstantHash.DELETE;
976 h_DoubleConstantHash.DELETE;
977 h_MethodDescriptorHash.DELETE;
978
979 END next_logic_segment;
980 ---------------------------------------------------------------------------------------
981 -- Scope: compile_logic_file
982 PROCEDURE spool_logic_file IS
983
984 l_file_id NUMBER;
985 l_loc BLOB;
986
987 BEGIN
988
989 flush_constant_pool ();
990 flush_code_memory ();
991
992 IF ( pool_ptr + code_ptr > 0 ) THEN
993
994 DBMS_LOB.CREATETEMPORARY ( l_loc, TRUE );
995
996 IF ( pool_ptr > 0 ) THEN DBMS_LOB.APPEND ( l_loc, ConstantPool ); END IF;
997 IF ( code_ptr > 0 ) THEN DBMS_LOB.APPEND ( l_loc, CodeMemory ); END IF;
998
999 DBMS_LOB.WRITEAPPEND ( l_loc, 4, cz_fce_compile_utils.integer_raw ( pool_ptr ));
1000 DBMS_LOB.WRITEAPPEND ( l_loc, 4, const_file_signature );
1001
1002 IF ( this_segment_nbr = 1 ) THEN
1003
1004 SELECT cz_fce_files_s.NEXTVAL INTO this_file_id FROM DUAL;
1005
1006 --This does not delete a logic file if there is no such type in the current generation.
1007 --For example, if an only port has been removed from the model, there will be no port
1008 --file in this generation, so the current port file will not be deleted.
1009
1010 --#<problem>
1011 --Need a better handling of this problem. For now we will always create files of all
1012 --possible types even if they are empty. We do that for rule files anyway.
1013
1014 UPDATE cz_fce_files SET deleted_flag = '1'
1015 WHERE component_id = p_component_id
1016 AND fce_file_type = p_type;
1017
1018 ELSE
1019
1020 --Need that in case we are restoring to a savepoint in the previous segment.
1021
1022 DELETE FROM cz_fce_files
1023 WHERE component_id = p_component_id
1024 AND fce_file_type = p_type
1025 AND segment_nbr = this_segment_nbr;
1026
1027 END IF;
1028
1029 INSERT INTO cz_fce_files ( FCE_FILE_ID
1030 , FCE_FILE_TYPE
1031 , COMPONENT_ID
1032 , SEGMENT_NBR
1033 , FCE_FILE
1034 , DELETED_FLAG
1035 , DEBUG_FLAG
1036 )
1037 VALUES ( this_file_id
1038 , p_type
1039 , p_component_id
1040 , this_segment_nbr
1041 , l_loc
1042 , '0'
1043 , TO_CHAR ( p_debug_mode )
1044 );
1045 END IF;
1046 END spool_logic_file;
1047 ---------------------------------------------------------------------------------------
1048 -- Scope: compile_logic_file
1049 PROCEDURE emit_code ( p_code IN RAW ) IS
1050
1051 l_code VARCHAR2(128 BYTE) := RAWTOHEX ( p_code );
1052 l_len BINARY_INTEGER := LENGTHB ( l_code );
1053
1054 BEGIN
1055
1056 code_buffer_ptr := code_buffer_ptr + l_len;
1057 code_ptr := code_ptr + UTL_RAW.LENGTH ( p_code );
1058
1059 IF ( code_buffer_ptr >= const_codememory_buffersize ) THEN
1060
1061 flush_code_memory ();
1062
1063 CodeMemory_buffer := NULL;
1064 code_buffer_ptr := l_len;
1065
1066 END IF;
1067
1068 CodeMemory_buffer := CodeMemory_buffer || l_code;
1069
1070 END emit_code;
1071 ---------------------------------------------------------------------------------------
1072 -- Scope: compile_logic_file
1073 FUNCTION emit_data ( p_data IN RAW ) RETURN PLS_INTEGER IS
1074
1075 l_pool_ptr PLS_INTEGER;
1076 l_len BINARY_INTEGER := UTL_RAW.LENGTH ( p_data );
1077
1078 l_data VARCHAR2(32767 BYTE) := RAWTOHEX ( p_data );
1079 l_data_len BINARY_INTEGER := LENGTHB ( l_data );
1080
1081 BEGIN
1082
1083 IF ( pool_ptr >= const_constantpool_maxsize ) THEN
1084
1085 --Here the switch to the next logic file will be handled. The switch will occur
1086 --when the constant pool overflown.
1087
1088 emit_code ( h_inst ('ret'));
1089 spool_logic_file ();
1090
1091 next_logic_segment ();
1092
1093 END IF;
1094
1095 IF ( l_data_len >= const_constantpool_buffersize ) THEN
1096
1097 flush_constant_pool ();
1098
1099 DBMS_LOB.WRITEAPPEND ( ConstantPool, l_len, p_data );
1100
1101 ConstantPool_buffer := NULL;
1102 pool_buffer_ptr := 0;
1103
1104 ELSE
1105
1106 pool_buffer_ptr := pool_buffer_ptr + l_data_len;
1107
1108 IF ( pool_buffer_ptr >= const_constantpool_buffersize ) THEN
1109
1110 flush_constant_pool ();
1111
1112 ConstantPool_buffer := NULL;
1113 pool_buffer_ptr := l_data_len;
1114
1115 END IF;
1116
1117 ConstantPool_buffer := ConstantPool_buffer || l_data;
1118
1119 END IF;
1120
1121 l_pool_ptr := pool_ptr;
1122 pool_ptr := pool_ptr + l_len;
1123
1124 RETURN l_pool_ptr;
1125
1126 END emit_data;
1127 ---------------------------------------------------------------------------------------
1128 --Savepoints allow to delete partially generated byte-code when generation fails.
1129 -- Scope: compile_logic_file
1130 PROCEDURE set_savepoint IS
1131 BEGIN
1132
1133 segment_nbr_svp := this_segment_nbr;
1134
1135 code_ptr_svp := code_ptr;
1136 pool_ptr_svp := pool_ptr;
1137
1138 h_StringConstantHash_svp := h_StringConstantHash;
1139 h_IntegerConstantHash_svp := h_IntegerConstantHash;
1140 h_LongConstantHash_svp := h_LongConstantHash;
1141 h_MaskConstantHash_svp := h_MaskConstantHash;
1142 h_DoubleConstantHash_svp := h_DoubleConstantHash;
1143 h_MethodDescriptorHash_svp := h_MethodDescriptorHash;
1144
1145 h_LocalVariableHash_svp := h_LocalVariableHash;
1146 h_RegisterHash_svp := h_RegisterHash;
1147
1148 END set_savepoint;
1149 ---------------------------------------------------------------------------------------
1150 -- Scope: compile_logic_file
1151 PROCEDURE restore_savepoint IS
1152
1153 l_size PLS_INTEGER;
1154 l_tail PLS_INTEGER;
1155
1156 l_fce_file BLOB;
1157
1158 BEGIN
1159
1160 IF ( segment_nbr_svp < this_segment_nbr ) THEN
1161
1162 --This is a situation when the savepoint is in the previous segment, which has
1163 --already been saved to the database, for example segment switching occured in
1164 --in the middle of a rule generation, and this rule has to be rolled back. The
1165 --previous segment nees to be restored in memory from the database.
1166
1167 DBMS_LOB.TRIM ( ConstantPool, 0 );
1168 DBMS_LOB.TRIM ( CodeMemory, 0 );
1169
1170 SELECT fce_file INTO l_fce_file FROM cz_fce_files
1171 WHERE deleted_flag = '0'
1172 AND component_id = p_component_id
1173 AND fce_file_type = p_type
1174 AND segment_nbr = segment_nbr_svp;
1175
1176 --According to the logic file format, second four bytes from the end store the
1177 --size of the Constant Pool.
1178
1179 l_size := UTL_RAW.CAST_TO_BINARY_INTEGER ( DBMS_LOB.SUBSTR ( l_fce_file, 4, DBMS_LOB.GETLENGTH ( l_fce_file ) - 7 ));
1180 l_tail := DBMS_LOB.GETLENGTH ( l_fce_file ) - 8 - l_size;
1181
1182 IF ( l_size > 0 ) THEN ConstantPool := DBMS_LOB.SUBSTR ( l_fce_file, l_size, 1 ); END IF;
1183 IF ( l_tail > 0 ) THEN CodeMemory := DBMS_LOB.SUBSTR ( l_fce_file, l_tail, l_size + 1 ); END IF;
1184
1185 this_segment_nbr := segment_nbr_svp;
1186
1187 ELSE
1188
1189 flush_constant_pool ();
1190 flush_code_memory ();
1191
1192 END IF;
1193
1194 code_ptr := code_ptr_svp;
1195 pool_ptr := pool_ptr_svp;
1196
1197 DBMS_LOB.TRIM ( CodeMemory, code_ptr_svp );
1198 DBMS_LOB.TRIM ( ConstantPool, pool_ptr_svp );
1199
1200 CodeMemory_buffer := NULL;
1201 code_buffer_ptr := 0;
1202
1203 ConstantPool_buffer := NULL;
1204 pool_buffer_ptr := 0;
1205
1206 h_StringConstantHash := h_StringConstantHash_svp;
1207 h_IntegerConstantHash := h_IntegerConstantHash_svp;
1208 h_LongConstantHash := h_LongConstantHash_svp;
1209 h_MaskConstantHash := h_MaskConstantHash_svp;
1210 h_DoubleConstantHash := h_DoubleConstantHash_svp;
1211 h_MethodDescriptorHash := h_MethodDescriptorHash_svp;
1212
1213 h_LocalVariableHash := h_LocalVariableHash_svp;
1214 h_RegisterHash := h_RegisterHash_svp;
1215
1216 END restore_savepoint;
1217 ---------------------------------------------------------------------------------------
1218 -------------------------- LOGIC FILE IMPLEMENTATION ----------------------------------
1219 ---------------------------------------------------------------------------------------
1220 -- Scope: compile_logic_file
1221 PROCEDURE emit_ldc ( p_ptr IN PLS_INTEGER ) IS
1222 BEGIN
1223
1224 IF ( cz_fce_compile_utils.assert_unsigned_byte ( p_ptr )) THEN
1225
1226 emit_code ( h_inst ('ldc') || cz_fce_compile_utils.unsigned_byte ( p_ptr ));
1227
1228 ELSIF ( cz_fce_compile_utils.assert_unsigned_word ( p_ptr )) THEN
1229
1230 emit_code ( h_inst ('ldc_w') || cz_fce_compile_utils.unsigned_word ( p_ptr ));
1231
1232 ELSE
1233
1234 report_and_raise_sys_error(
1235 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_POINTER_TOO_LONG),
1236 p_run_id => x_run_id,
1237 p_model_id => p_component_id
1238 );
1239
1240 END IF;
1241 END emit_ldc;
1242 ---------------------------------------------------------------------------------------
1243 -- Scope: compile_logic_file
1244 PROCEDURE emit_iconst ( p_int IN NUMBER ) IS
1245 BEGIN
1246
1247 IF ( p_int = ( -1 )) THEN
1248
1249 emit_code ( h_inst ('iconst_m1'));
1250
1251 ELSE
1252
1253 emit_code ( h_inst ('iconst_' || TO_CHAR ( p_int )));
1254
1255 END IF;
1256 END emit_iconst;
1257 ---------------------------------------------------------------------------------------
1258 -- Scope: compile_logic_file
1259 PROCEDURE emit_dup IS
1260 BEGIN
1261
1262 emit_code ( h_inst ('dup'));
1263
1264 END emit_dup;
1265 ---------------------------------------------------------------------------------------
1266 -- Scope: compile_logic_file
1267 PROCEDURE emit_swap IS
1268 BEGIN
1269
1270 emit_code ( h_inst ('swap'));
1271
1272 END emit_swap;
1273 ---------------------------------------------------------------------------------------
1274 -- Scope: compile_logic_file
1275 FUNCTION emit_string_constant ( p_string IN VARCHAR2 ) RETURN PLS_INTEGER IS
1276
1277 l_pool_ptr PLS_INTEGER;
1278
1279 BEGIN
1280
1281 IF (NOT h_StringConstantHash.EXISTS( p_string )) THEN
1282
1283 --This uses the format of string constant entry in the constant pool. If the format changes,
1284 --this will have to change.
1285 --#<constant pool format>
1286
1287 IF ( cz_fce_compile_utils.assert_unsigned_word ( LENGTHB ( p_string ))) THEN
1288
1289 l_pool_ptr := emit_data ( const_string_tag || cz_fce_compile_utils.unsigned_word ( LENGTHB ( p_string )) ||
1290 UTL_RAW.CAST_TO_RAW ( p_string ));
1291 h_StringConstantHash( p_string ) := l_pool_ptr;
1292
1293 ELSE
1294
1295 report_and_raise_sys_error(
1296 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_STRING_TOO_LONG),
1297 p_run_id => x_run_id,
1298 p_model_id => p_component_id
1299 );
1300
1301 END IF;
1302
1303 ELSE
1304
1305 l_pool_ptr := h_StringConstantHash( p_string );
1306
1307 END IF;
1308 RETURN l_pool_ptr;
1309
1310 END emit_string_constant;
1311 ---------------------------------------------------------------------------------------
1312 -- Scope: compile_logic_file
1313 FUNCTION emit_integer_constant ( p_int IN NUMBER ) RETURN PLS_INTEGER IS
1314
1315 l_key VARCHAR2(4000) := TO_CHAR (p_int);
1316 l_ptr PLS_INTEGER;
1317
1318 BEGIN
1319
1320 IF (NOT h_IntegerConstantHash.EXISTS ( l_key )) THEN
1321
1322 --#<constant pool format>
1323
1324 l_ptr := emit_data ( const_integer_tag || cz_fce_compile_utils.integer_raw ( p_int ));
1325 h_IntegerConstantHash( l_key ) := l_ptr;
1326
1327 ELSE
1328
1329 l_ptr := h_IntegerConstantHash ( l_key );
1330
1331 END IF;
1332 RETURN l_ptr;
1333 END emit_integer_constant;
1334 ---------------------------------------------------------------------------------------
1335 -- Scope: compile_logic_file
1336 FUNCTION emit_long_constant ( p_int IN NUMBER ) RETURN PLS_INTEGER IS
1337
1338 l_key VARCHAR2(4000) := TO_CHAR ( p_int );
1339 l_ptr PLS_INTEGER;
1340
1341 BEGIN
1342
1343 IF (NOT h_LongConstantHash.EXISTS ( l_key )) THEN
1344
1345 --#<constant pool format>
1346
1347 l_ptr := emit_data ( const_long_tag || cz_fce_compile_utils.long_raw ( p_int ));
1348 h_LongConstantHash( l_key ) := l_ptr;
1349
1350 ELSE
1351
1352 l_ptr := h_LongConstantHash ( l_key );
1353
1354 END IF;
1355 RETURN l_ptr;
1356 END emit_long_constant;
1357 ---------------------------------------------------------------------------------------
1358 -- Scope: compile_logic_file
1359 --This functions emits a string of 16 hex characters as a long.
1360 --Example: effective_usage_mask
1361 FUNCTION emit_mask_constant ( p_mask IN VARCHAR2 ) RETURN PLS_INTEGER IS
1362
1363 l_ptr PLS_INTEGER;
1364
1365 BEGIN
1366
1367 IF (NOT h_MaskConstantHash.EXISTS ( p_mask )) THEN
1368
1369 --#<constant pool format> long constant.
1370
1371 l_ptr := emit_data ( const_long_tag || HEXTORAW ( p_mask ));
1372 h_MaskConstantHash( p_mask ) := l_ptr;
1373
1374 ELSE
1375
1376 l_ptr := h_MaskConstantHash ( p_mask );
1377
1378 END IF;
1379 RETURN l_ptr;
1380 END emit_mask_constant;
1381 ---------------------------------------------------------------------------------------
1382 --Scope: compile_logic_file
1383 --This functions emits a date in Java's long representation.
1384 --Example: effective_from, effective_until
1385 FUNCTION emit_date_constant ( p_date IN DATE ) RETURN PLS_INTEGER IS
1386
1387 l_num NUMBER := ( p_date - const_java_epoch_begin ) * 86400000;
1388 l_key VARCHAR2(4000) := TO_CHAR ( l_num );
1389 l_ptr PLS_INTEGER;
1390
1391 BEGIN
1392
1393 IF (NOT h_LongConstantHash.EXISTS ( l_key )) THEN
1394
1395 --#<constant pool format>
1396
1397 l_ptr := emit_data ( const_date_tag || cz_fce_compile_utils.long_raw ( l_num ));
1398 h_LongConstantHash ( l_key ) := l_ptr;
1399
1400 ELSE
1401
1402 l_ptr := h_LongConstantHash ( l_key );
1403
1404 END IF;
1405 RETURN l_ptr;
1406 END emit_date_constant;
1407 ---------------------------------------------------------------------------------------
1408 -- Scope: compile_logic_file
1409 FUNCTION emit_double_constant ( p_number IN NUMBER ) RETURN PLS_INTEGER IS
1410
1411 l_ptr PLS_INTEGER;
1412 l_key VARCHAR2(4000) := TO_CHAR ( p_number );
1413
1414 BEGIN
1415
1416 IF (NOT h_DoubleConstantHash.EXISTS ( l_key )) THEN
1417
1418 --#<constant pool format>
1419
1420 l_ptr := emit_data ( const_double_tag || cz_fce_compile_utils.double_raw ( p_number ));
1421 h_DoubleConstantHash ( l_key ) := l_ptr;
1422
1423 ELSE
1424
1425 l_ptr := h_DoubleConstantHash ( l_key );
1426
1427 END IF;
1428 RETURN l_ptr;
1429 END emit_double_constant;
1430 ---------------------------------------------------------------------------------------
1431 -- Scope: compile_logic_file
1432 PROCEDURE push_string_constant ( p_string IN VARCHAR2 ) IS
1433 BEGIN
1434
1435 emit_ldc ( emit_string_constant ( p_string ));
1436
1437 END push_string_constant;
1438 ---------------------------------------------------------------------------------------
1439 -- Scope: compile_logic_file
1440 PROCEDURE push_double_constant ( p_number IN NUMBER ) IS
1441 BEGIN
1442
1443 emit_ldc ( emit_double_constant ( p_number ));
1444
1445 END push_double_constant;
1446 ---------------------------------------------------------------------------------------
1447 -- Scope: compile_logic_file
1448 PROCEDURE push_mask_constant ( p_mask IN VARCHAR2 ) IS
1449 BEGIN
1450
1451 emit_ldc ( emit_mask_constant ( p_mask ));
1452
1453 END push_mask_constant;
1454 ---------------------------------------------------------------------------------------
1455 -- Scope: compile_logic_file
1456 PROCEDURE push_date_constant ( p_date IN DATE ) IS
1457 BEGIN
1458
1459 emit_ldc ( emit_date_constant ( p_date ));
1460
1461 END push_date_constant;
1462 ---------------------------------------------------------------------------------------
1463 -- Scope: compile_logic_file
1464 --This procedure is different from the push_long_constant in that it does not go
1465 --beyond integer. This is useful when we need to be sure that the number is not
1466 --long, for example when pushing an array size or integer parameters.
1467
1468 PROCEDURE push_integer_constant ( p_int IN PLS_INTEGER ) IS
1469 BEGIN
1470
1471 IF ( cz_fce_compile_utils.assert_iconst ( p_int )) THEN
1472
1473 emit_iconst ( p_int );
1474
1475 ELSIF ( cz_fce_compile_utils.assert_byte ( p_int )) THEN
1476
1477 emit_code ( h_inst ('bipush') || cz_fce_compile_utils.byte ( p_int ));
1478
1479 ELSIF ( cz_fce_compile_utils.assert_word ( p_int )) THEN
1480
1481 emit_code ( h_inst ('sipush') || cz_fce_compile_utils.word ( p_int ));
1482
1483 ELSIF ( cz_fce_compile_utils.assert_integer ( p_int )) THEN
1484
1485 emit_ldc ( emit_integer_constant ( p_int ));
1486
1487 ELSE
1488
1489 report_and_raise_sys_error(
1490 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_INTEGER_TOO_LONG, 'VALUE', TO_CHAR ( p_int )),
1491 p_run_id => x_run_id,
1492 p_model_id => p_component_id
1493 );
1494
1495 END IF;
1496 END push_integer_constant;
1497 ---------------------------------------------------------------------------------------
1498 -- Scope: compile_logic_file
1499 PROCEDURE push_long_constant ( p_int IN NUMBER ) IS
1500
1501 l_ptr PLS_INTEGER;
1502
1503 BEGIN
1504
1505 IF ( cz_fce_compile_utils.assert_integer ( p_int )) THEN
1506
1507 push_integer_constant ( p_int );
1508
1509 ELSIF ( cz_fce_compile_utils.assert_long ( p_int )) THEN
1510
1511 emit_ldc ( emit_long_constant ( p_int ));
1512
1513 ELSE
1514
1515 report_and_raise_sys_error(
1516 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_LONG_TOO_LONG, 'VALUE', TO_CHAR ( p_int )),
1517 p_run_id => x_run_id,
1518 p_model_id => p_component_id
1519 );
1520
1521 END IF;
1522 END push_long_constant;
1523 ---------------------------------------------------------------------------------------
1524 -- Scope: compile_logic_file
1525 --This procedure tries to push the decimal in the most economical way, first as an
1526 --integer, if that fails as a 4-byte float and if that fails - as a 8-byte double.
1527 --If there are any problems in Java with implicit conversions, we may need to give
1528 --up using float constants at all, and this procedure will just push double.
1529
1530 --Bug #6730258 shows, that we have to give up trying to store decimal constants as
1531 --floats. All procedures working with float numbers are removed from this package.
1532 --They can also be removed from cz_fce_compile_utils and ConstantPool class.
1533
1534 PROCEDURE push_decimal_constant ( p_number IN NUMBER ) IS
1535 BEGIN
1536
1537 IF ( ROUND ( p_number ) = p_number AND cz_fce_compile_utils.assert_long ( p_number )) THEN
1538
1539 push_long_constant ( p_number );
1540
1541 ELSE
1542
1543 push_double_constant ( p_number );
1544
1545 END IF;
1546 END push_decimal_constant;
1547 ---------------------------------------------------------------------------------------
1548 -- Scope: compile_logic_file
1549 PROCEDURE emit_pop ( p_elements IN PLS_INTEGER ) IS
1550 BEGIN
1551
1552 IF ( p_elements = 0 ) THEN
1553
1554 RETURN;
1555
1556 ELSIF ( p_elements = 1 ) THEN
1557
1558 emit_code( h_inst('pop'));
1559
1560 ELSE
1561
1562 push_integer_constant ( p_elements );
1563 emit_code( h_inst('mpop'));
1564
1565 END IF;
1566 END emit_pop;
1567 ---------------------------------------------------------------------------------------
1568 -- Scope: compile_logic_file
1569 FUNCTION emit_method_descriptor ( p_ptr IN PLS_INTEGER ) RETURN PLS_INTEGER IS
1570
1571 l_ptr PLS_INTEGER;
1572
1573 BEGIN
1574
1575 IF (NOT h_MethodDescriptorHash.EXISTS( p_ptr )) THEN
1576
1577 IF ( cz_fce_compile_utils.assert_unsigned_byte( p_ptr )) THEN
1578
1579 l_ptr := emit_data(const_method_tag || cz_fce_compile_utils.unsigned_byte( p_ptr ));
1580 h_MethodDescriptorHash( p_ptr ) := l_ptr;
1581
1582 ELSE
1583
1584 report_and_raise_sys_error(
1585 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_METHODIX_OUTOFRANGE, 'VALUE', TO_CHAR ( p_ptr )),
1586 p_run_id => x_run_id,
1587 p_model_id => p_component_id
1588 );
1589
1590 END IF;
1591
1592 ELSE
1593
1594 l_ptr := h_MethodDescriptorHash( p_ptr );
1595
1596 END IF;
1597 RETURN l_ptr;
1598 END emit_method_descriptor;
1599 ---------------------------------------------------------------------------------------
1600 -- Scope: compile_logic_file
1601 PROCEDURE emit_invokestatic ( p_signature IN VARCHAR2 ) IS
1602 BEGIN
1603
1604 emit_code(h_inst('invokestatic') ||
1605 cz_fce_compile_utils.unsigned_word ( emit_method_descriptor ( h_methoddescriptors ( p_signature ))));
1606
1607 END emit_invokestatic;
1608 ---------------------------------------------------------------------------------------
1609 -- Scope: compile_logic_file
1610 PROCEDURE emit_invokevirtual ( p_signature IN VARCHAR2 ) IS
1611 BEGIN
1612
1613 emit_code(h_inst('invokevirtual') ||
1614 cz_fce_compile_utils.unsigned_word ( emit_method_descriptor ( h_methoddescriptors ( p_signature ))));
1615
1616 END emit_invokevirtual;
1617 ---------------------------------------------------------------------------------------
1618 -- Scope: compile_logic_file
1619 PROCEDURE emit_regop ( p_ptr IN PLS_INTEGER, p_op IN VARCHAR2 ) IS
1620 BEGIN
1621
1622 IF ( p_op NOT IN ( 'astore', 'copyto', 'aload' )) THEN
1623
1624 report_and_raise_sys_error(
1625 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_UNKNOWN_OPERATION, 'OPERATION', p_op),
1626 p_run_id => x_run_id,
1627 p_model_id => p_component_id
1628 );
1629
1630 END IF;
1631
1632 IF ( NOT cz_fce_compile_utils.assert_unsigned_byte ( p_ptr )) THEN
1633
1634 report_and_raise_sys_error(
1635 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_INVALID_ACCESS_VAR, 'OPERATION', p_op, 'VAR', TO_CHAR ( p_ptr )),
1636 p_run_id => x_run_id,
1637 p_model_id => p_component_id
1638 );
1639
1640 END IF;
1641
1642 IF ( p_ptr < 4 ) THEN
1643
1644 emit_code ( h_inst ( p_op || '_' || TO_CHAR ( p_ptr )));
1645
1646 ELSE
1647
1648 emit_code ( h_inst ( p_op ) || cz_fce_compile_utils.unsigned_byte ( p_ptr ));
1649
1650 END IF;
1651 END emit_regop;
1652 ---------------------------------------------------------------------------------------
1653 -- Scope: compile_logic_file
1654 PROCEDURE emit_regop_w ( p_ptr IN PLS_INTEGER, p_op IN VARCHAR2 ) IS
1655 BEGIN
1656
1657 IF ( p_op NOT IN ( 'astore', 'copyto', 'aload' )) THEN
1658
1659 report_and_raise_sys_error(
1660 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_UNKNOWN_OPERATION, 'OPERATION', p_op || '_w'),
1661 p_run_id => x_run_id,
1662 p_model_id => p_component_id
1663 );
1664
1665 END IF;
1666
1667 IF ( NOT cz_fce_compile_utils.assert_unsigned_word ( p_ptr )) THEN
1668
1669 report_and_raise_sys_error(
1670 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_INVALID_ACCESS_VARW, 'OPERATION', p_op, 'VAR', TO_CHAR ( p_ptr )),
1671 p_run_id => x_run_id,
1672 p_model_id => p_component_id
1673 );
1674
1675 END IF;
1676
1677 emit_code ( h_inst ( p_op || '_w') || cz_fce_compile_utils.unsigned_word ( p_ptr ));
1678
1679 END emit_regop_w;
1680 ---------------------------------------------------------------------------------------
1681 -- Scope: compile_logic_file
1682 PROCEDURE emit_boolean ( p_value IN VARCHAR2 ) IS
1683 BEGIN
1684
1685 IF ( p_value = '0' ) THEN
1686
1687 emit_code ( h_inst ('pushfalse'));
1688
1689 ELSE
1690
1691 emit_code ( h_inst ('pushtrue'));
1692
1693 END IF;
1694 END emit_boolean;
1695 ---------------------------------------------------------------------------------------
1696 -- Scope: compile_logic_file
1697 PROCEDURE emit_constant ( p_int IN NUMBER ) IS
1698 BEGIN
1699
1700 emit_code ( h_inst ('pushmath') || cz_fce_compile_utils.unsigned_byte ( p_int ));
1701
1702 END emit_constant;
1703 ---------------------------------------------------------------------------------------
1704 PROCEDURE emit_comment ( p_string IN VARCHAR2 ) IS
1705 BEGIN
1706
1707 emit_code ( h_inst ('comment') || cz_fce_compile_utils.unsigned_word ( emit_string_constant ( p_string )));
1708
1709 END emit_comment;
1710 ---------------------------------------------------------------------------------------
1711 --The Interpreter has 2 hastore instructions:
1712 --hastore_0 stores in the internal hash #0;
1713 --hastore_1 stores in the internal hash #1.
1714 -- Scope: compile_logic_file
1715 PROCEDURE hastore_object ( p_id IN NUMBER, p_hash IN PLS_INTEGER ) IS
1716 BEGIN
1717
1718 push_long_constant( p_id );
1719 emit_code ( h_inst ( 'hastore_' || TO_CHAR ( p_hash )));
1720
1721 END hastore_object;
1722 ---------------------------------------------------------------------------------------
1723 --The Interpreter has 3 haload instructions, this procedure handles 2 of them:
1724 --haload_0 loads from the internal hash #0;
1725 --haload_1 loads from the internal hash #1;
1726 -- Scope: compile_logic_file
1727 PROCEDURE haload_object ( p_id IN NUMBER, p_hash IN PLS_INTEGER ) IS
1728 BEGIN
1729
1730 push_long_constant ( p_id );
1731 emit_code (h_inst ( 'haload_' || TO_CHAR ( p_hash )));
1732
1733 END haload_object;
1734 ---------------------------------------------------------------------------------------
1735 -- Scope: compile_logic_file
1736 PROCEDURE haload2_object ( p_ref_id IN NUMBER ) IS
1737 BEGIN
1738
1739 push_long_constant( p_ref_id );
1740 emit_code ( h_inst ( 'haload_2'));
1741
1742 END haload2_object;
1743 ---------------------------------------------------------------------------------------
1744 -- Scope: compile_logic_file
1745 FUNCTION allocate_local_variable RETURN PLS_INTEGER IS
1746
1747 l_ptr PLS_INTEGER := localvariable_ptr;
1748
1749 BEGIN
1750
1751 IF ( localvariable_ptr < const_max_localvariables ) THEN
1752
1753 localvariable_ptr := localvariable_ptr + 1;
1754
1755 ELSE
1756
1757 --All local variables are allocated, select a local variables to use.
1758 --Algorithms, like 'least used' variable, can be implemented here.
1759
1760 localvariable_ptr := 0;
1761 l_ptr := 0;
1762
1763 END IF;
1764
1765 --Important: if the allocated local variable was used to store an object
1766 --and now is being overloaded, we need to disassociate that object with
1767 --this local variable otherwise code may think that this object is still
1768 --stored in this variable.
1769
1770 IF (h_LocalVariableBackPtr.EXISTS( l_ptr )) THEN
1771
1772 h_LocalVariableHash.DELETE(h_LocalVariableBackPtr( l_ptr ));
1773
1774 END IF;
1775
1776 RETURN l_ptr;
1777 END allocate_local_variable;
1778 ---------------------------------------------------------------------------------------
1779 -- Scope: compile_logic_file
1780 FUNCTION local_variable_defined ( p_key IN VARCHAR ) RETURN BOOLEAN IS
1781 BEGIN
1782
1783 RETURN h_LocalVariableHash.EXISTS( p_key );
1784
1785 END local_variable_defined;
1786 ---------------------------------------------------------------------------------------
1787 -- Scope: compile_logic_file
1788 FUNCTION local_variable_index ( p_key IN VARCHAR2 ) RETURN PLS_INTEGER IS
1789
1790 l_ptr PLS_INTEGER;
1791
1792 BEGIN
1793
1794 --Note, that this implementation re-writes a local variable, if such variable has
1795 --already been allocated for the key. This is done in order to allow many-to-one
1796 --object-key relation, for example, several root expressions in the same rule can
1797 --be keyed by rule_id and stored in the same variable one after another.
1798
1799 IF ( NOT local_variable_defined ( p_key )) THEN
1800
1801 l_ptr := allocate_local_variable ();
1802 h_LocalVariableHash( p_key ) := l_ptr;
1803 h_LocalVariableBackPtr( l_ptr ) := p_key;
1804
1805 ELSE
1806
1807 l_ptr := h_LocalVariableHash ( p_key );
1808
1809 END IF;
1810
1811 RETURN l_ptr;
1812 END local_variable_index;
1813 ---------------------------------------------------------------------------------------
1814 -- Scope: compile_logic_file
1815 PROCEDURE astore_local_variable ( p_key IN VARCHAR2 ) IS
1816 BEGIN
1817
1818 emit_regop ( local_variable_index ( p_key ), 'astore' );
1819
1820 END astore_local_variable;
1821 ---------------------------------------------------------------------------------------
1822 -- Scope: compile_logic_file
1823 PROCEDURE copyto_local_variable ( p_id IN NUMBER ) IS
1824 BEGIN
1825
1826 emit_regop ( local_variable_index ( TO_CHAR( p_id )), 'copyto' );
1827
1828 END copyto_local_variable;
1829 ---------------------------------------------------------------------------------------
1830 -- Scope: compile_logic_file
1831 PROCEDURE copyto_local_variable ( p_key IN VARCHAR2 ) IS
1832 BEGIN
1833
1834 emit_regop ( local_variable_index ( p_key ), 'copyto' );
1835
1836 END copyto_local_variable;
1837 ---------------------------------------------------------------------------------------
1838 -- Scope: compile_logic_file
1839 PROCEDURE aload_local_variable ( p_key IN VARCHAR2 ) IS
1840 BEGIN
1841
1842 IF ( NOT local_variable_defined ( p_key )) THEN
1843
1844 --#<should never happen>
1845 report_and_raise_sys_error(
1846 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_UNDEFINED_LOCAL_VAR, 'KEY', p_key),
1847 p_run_id => x_run_id,
1848 p_model_id => p_component_id
1849 );
1850
1851 END IF;
1852
1853 emit_regop ( h_LocalVariableHash ( p_key ), 'aload' );
1854
1855 END aload_local_variable;
1856 ---------------------------------------------------------------------------------------
1857 ---------------------------------------------------------------------------------------
1858 -- Scope: compile_logic_file
1859 PROCEDURE free_registers IS
1860 BEGIN
1861
1862 register_ptr := 0;
1863 h_RegisterHash.DELETE;
1864
1865 END free_registers;
1866 ---------------------------------------------------------------------------------------
1867 -- Scope: compile_logic_file
1868 FUNCTION allocate_register RETURN PLS_INTEGER IS
1869
1870 l_ptr PLS_INTEGER := register_ptr;
1871
1872 BEGIN
1873
1874 IF ( register_ptr >= const_max_registers ) THEN
1875
1876 report_and_raise_sys_error(
1877 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_NO_MORE_REGISTERS),
1878 p_run_id => x_run_id,
1879 p_model_id => p_component_id
1880 );
1881 END IF;
1882
1883 register_ptr := register_ptr + 1;
1884
1885 RETURN l_ptr;
1886 END allocate_register;
1887 ---------------------------------------------------------------------------------------
1888 -- Scope: compile_logic_file
1889 FUNCTION register_defined ( p_key IN VARCHAR ) RETURN BOOLEAN IS
1890 BEGIN
1891
1892 RETURN h_RegisterHash.EXISTS( p_key );
1893
1894 END register_defined;
1895 ---------------------------------------------------------------------------------------
1896 -- Scope: compile_logic_file
1897 FUNCTION register_index ( p_key IN VARCHAR2 ) RETURN PLS_INTEGER IS
1898
1899 l_ptr PLS_INTEGER;
1900
1901 BEGIN
1902
1903 --Note, that this implementation re-writes a local variable, if such variable has
1904 --already been allocated for the key.
1905
1906 IF ( NOT register_defined ( p_key )) THEN
1907
1908 l_ptr := allocate_register ();
1909 h_RegisterHash( p_key ) := l_ptr;
1910
1911 ELSE
1912
1913 l_ptr := h_RegisterHash ( p_key );
1914
1915 END IF;
1916
1917 RETURN l_ptr;
1918 END register_index;
1919 ---------------------------------------------------------------------------------------
1920 -- Scope: compile_logic_file
1921 PROCEDURE astore_register ( p_key IN VARCHAR2 ) IS
1922 BEGIN
1923
1924 emit_regop_w ( register_index ( p_key ), 'astore' );
1925
1926 END astore_register;
1927 ---------------------------------------------------------------------------------------
1928 -- Scope: compile_logic_file
1929 PROCEDURE copyto_register ( p_key IN VARCHAR2 ) IS
1930 BEGIN
1931
1932 emit_regop_w ( register_index ( p_key ), 'copyto' );
1933
1934 END copyto_register;
1935 ---------------------------------------------------------------------------------------
1936 -- Scope: compile_logic_file
1937 PROCEDURE aload_register ( p_key IN VARCHAR2 ) IS
1938 BEGIN
1939
1940 IF ( NOT register_defined ( p_key )) THEN
1941
1942 --#<should never happen>
1943 report_and_raise_sys_error(
1944 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_UNDEFINED_REGISTER, 'KEY', p_key),
1945 p_run_id => x_run_id,
1946 p_model_id => p_component_id
1947 );
1948
1949 END IF;
1950
1951 emit_regop_w ( h_RegisterHash ( p_key ), 'aload' );
1952
1953 END aload_register;
1954 ---------------------------------------------------------------------------------------
1955 ---------------------------------------------------------------------------------------
1956 -- Scope: compile_logic_file
1957 PROCEDURE create_array ( p_size IN PLS_INTEGER, p_type IN PLS_INTEGER ) IS
1958 BEGIN
1959
1960 IF ( NOT cz_fce_compile_utils.assert_unsigned_byte ( p_type )) THEN
1961
1962 report_and_raise_sys_error(
1963 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_INCORRECT_IX, 'VALUE', TO_CHAR ( p_type )),
1964 p_run_id => x_run_id,
1965 p_model_id => p_component_id
1966 );
1967
1968 END IF;
1969
1970 push_integer_constant ( p_size );
1971 emit_code( h_inst ('newarray') || cz_fce_compile_utils.unsigned_byte ( p_type ));
1972
1973 END create_array;
1974 ---------------------------------------------------------------------------------------
1975 -- Scope: compile_logic_file
1976 PROCEDURE populate_array_element ( p_index IN PLS_INTEGER ) IS
1977 BEGIN
1978
1979 push_integer_constant ( p_index );
1980 emit_code( h_inst ('aastore'));
1981
1982 END populate_array_element;
1983 ---------------------------------------------------------------------------------------
1984 -- Scope: compile_logic_file
1985 PROCEDURE populate_array ( p_size IN PLS_INTEGER ) IS
1986 BEGIN
1987
1988 push_integer_constant ( p_size );
1989 emit_code( h_inst ('bulkaastore'));
1990
1991 END populate_array;
1992 ---------------------------------------------------------------------------------------
1993 -- Scope: compile_logic_file
1994 PROCEDURE create_multi_array ( p_sizes IN type_integer_table, p_type IN PLS_INTEGER ) IS
1995
1996 l_count PLS_INTEGER;
1997
1998 BEGIN
1999
2000 IF ( NOT cz_fce_compile_utils.assert_unsigned_byte ( p_type )) THEN
2001
2002 report_and_raise_sys_error(
2003 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_INCORRECT_IX, 'VALUE', TO_CHAR ( p_type )),
2004 p_run_id => x_run_id,
2005 p_model_id => p_component_id
2006 );
2007
2008 END IF;
2009
2010 l_count := p_sizes.COUNT;
2011
2012 IF ( NOT cz_fce_compile_utils.assert_unsigned_byte ( l_count )) THEN
2013
2014 report_and_raise_sys_error(
2015 p_message => GET_NOT_TRANSLATED_TEXT(CZ_FCE_SE_EXCEED_INTTABLESIZE, 'VALUE', TO_CHAR ( l_count )),
2016 p_run_id => x_run_id,
2017 p_model_id => p_component_id
2018 );
2019
2020 END IF;
2021
2022 FOR i IN REVERSE 1..l_count LOOP
2023
2024 push_integer_constant ( p_sizes ( i ));
2025
2026 END LOOP;
2027
2028 emit_code( h_inst ('multinewarray') || cz_fce_compile_utils.unsigned_byte ( l_count ) ||
2029 cz_fce_compile_utils.unsigned_byte ( p_type ));
2030
2031 END create_multi_array;
2032 ---------------------------------------------------------------------------------------
2033 -- Scope: compile_logic_file
2034 PROCEDURE emit_return IS
2035 BEGIN
2036
2037 IF ( p_type = const_logicfile_def ) THEN
2038
2039 emit_code ( h_inst ('areturn'));
2040
2041 ELSE
2042
2043 emit_code ( h_inst ('ret'));
2044
2045 END IF;
2046 END emit_return;
2047 ---------------------------------------------------------------------------------------
2048 ------------------------------ HIGH LEVEL METHODS -------------------------------------
2049 ---------------------------------------------------------------------------------------
2050 PROCEDURE comment ( p_message IN VARCHAR2 ) IS
2051 BEGIN
2052
2053 IF ( p_debug_mode = 1 ) THEN
2054
2055 emit_comment ( p_message );
2056
2057 END IF;
2058 END comment;
2059 ---------------------------------------------------------------------------------------
2060 --This procedure writes to the Constant Pool and pushed a variable name to the stack.
2061 --In the debug mode, the variable name is the structure node name.
2062 --In the regular mode, the variable name is the persistent id (as a string).
2063 -- Scope: compile_logic_file
2064
2065 PROCEDURE push_variable_name ( p_index IN PLS_INTEGER ) IS
2066 BEGIN
2067
2068 IF ( p_debug_mode = 1 ) THEN
2069
2070 push_string_constant ( t_psn_name ( p_index ));
2071
2072 ELSE
2073
2074 push_string_constant( TO_CHAR ( t_psn_persistentnodeid ( p_index )));
2075
2076 END IF;
2077 END push_variable_name;
2078 ---------------------------------------------------------------------------------------
2079 --This is the same procedure as above, but the input parameter is ps_node_id.
2080 -- Scope: compile_logic_file
2081
2082 PROCEDURE push_variable_name ( p_id IN NUMBER ) IS
2083 BEGIN
2084
2085 IF ( p_debug_mode = 1 ) THEN
2086
2087 push_string_constant ( h_psnid_name ( TO_CHAR ( p_id )));
2088
2089 ELSE
2090
2091 push_string_constant( h_psnid_persistentnodeid ( TO_CHAR ( p_id )));
2092
2093 END IF;
2094 END push_variable_name;
2095 ---------------------------------------------------------------------------------------
2096 --This procedure is used to store model defs in the local hash.
2097 --Note that model defs are hashed by persistent_node_id.
2098
2099 --Here is why we need to hash by persistent_node_id, not ps_node_id. This procedure
2100 --will put a hash key on the stack and emit haload_0 instruction. The hash key will
2101 --be used to poke hash in order to get model def object. If there is no model def
2102 --for this key in the Interpreter's hash, the Interpreter must ask DIO for it.
2103 --DIO needs the referring node's persistent_node_id to be able to return model def.
2104 --So, to avoid conflicts, we need to always use persistent_node_id as the hash key.
2105
2106 --However, because of using persistent_node_id, the model def hash (#0) can only be
2107 --used for 'local' model defs, or model defs, that are directly referenced from the
2108 --'local' model, not for remote models defs, retrieved with haload_2.
2109
2110 -- Scope: compile_logic_file
2111
2112 PROCEDURE hastore_def ( p_index IN PLS_INTEGER ) IS
2113 BEGIN
2114
2115 hastore_object ( t_psn_persistentnodeid ( p_index ), 0);
2116
2117 END hastore_def;
2118 ---------------------------------------------------------------------------------------
2119 --This procedure is used to load model defs from the local hash.
2120
2121 --p_id - ps_node_id. Note that model defs are hashed by persistent_node_id.
2122 -- Scope: compile_logic_file
2123
2124 PROCEDURE haload_def ( p_id IN NUMBER ) IS
2125 BEGIN
2126
2127 haload_object ( h_psnid_persistentnodeid ( TO_CHAR ( p_id )), 0);
2128
2129 END haload_def;
2130 ---------------------------------------------------------------------------------------
2131 --This procedure is used to retrieve model definitions, stored in a local variable.
2132 --Model definitions use ps_node_id as a hash key to allocate local variables.
2133
2134 --Note that this procedure can be used as a universal access to 'local' model defs.
2135 --Even in port or constrain logic file, try to get model def from a local variable,
2136 --and if it is not there, get it from hash and store in a local variable.
2137
2138 --Made a change to use this procedure for access to 'local' model defs.
2139 -- Scope: compile_logic_file
2140
2141 PROCEDURE aload_model_def ( p_id IN NUMBER ) IS
2142
2143 l_key VARCHAR2(4000) := TO_CHAR ( p_id );
2144
2145 BEGIN
2146
2147 IF (NOT local_variable_defined ( l_key )) THEN
2148
2149 --Model defs are always stored both in local variables and in hash. So, if it's
2150 --not in a local variable, meaning that the local variable has been overloaded,
2151 --we can get it from hash and re-store in a local variable.
2152
2153 haload_def ( p_id );
2154 copyto_local_variable ( l_key );
2155
2156 ELSE
2157
2158 aload_local_variable ( l_key );
2159
2160 END IF;
2161 END aload_model_def;
2162 ---------------------------------------------------------------------------------------
2163 --This procedure is used to store Solver variables in the local hash.
2164
2165 --p_id - ps_node_id. Note that variable objects are hashed by ps_node_id.
2166 -- Scope: compile_logic_file
2167
2168 PROCEDURE hastore_var ( p_index IN PLS_INTEGER ) IS
2169 BEGIN
2170
2171 hastore_object ( t_psn_psnodeid ( p_index ), 1 );
2172
2173 END hastore_var;
2174 ---------------------------------------------------------------------------------------
2175 PROCEDURE push_modeldef_name ( p_index IN PLS_INTEGER ) IS
2176
2177 l_name VARCHAR2(4000);
2178
2179 BEGIN
2180
2181 --Bug #6926688. For root models, we need to specify the repository model name
2182 --instead of ps_node name. We don't need to handle no_data_found here because
2183 --it will not get this far without the data.
2184
2185 IF ( t_psn_parentid ( p_index ) IS NULL ) THEN
2186
2187 SELECT name INTO l_name FROM cz_rp_entries
2188 WHERE deleted_flag = '0'
2189 AND object_type = 'PRJ'
2190 AND object_id = t_psn_psnodeid ( p_index );
2191
2192 --Note that we always write name independently of debug mode.
2193
2194 push_string_constant ( l_name );
2195 comment ( 'Create model: "' || l_name || '" (model_id = ' || t_psn_psnodeid ( p_index ) || ')');
2196
2197 ELSE
2198
2199 push_variable_name ( p_index );
2200
2201 END IF;
2202 END push_modeldef_name;
2203 ---------------------------------------------------------------------------------------
2204 -- Scope: compile_logic_file
2205
2206 PROCEDURE emit_model_def ( p_index IN PLS_INTEGER ) IS
2207
2208 l_path VARCHAR2(32000);
2209 l_id NUMBER := t_psn_psnodeid ( p_index );
2210 l_parent_id NUMBER;
2211
2212 BEGIN
2213
2214 push_modeldef_name ( p_index );
2215 emit_invokestatic ('Solver.createModelDef(String)');
2216
2217 --If this is the root model, save the model def on stack to be returned at the
2218 --end.
2219
2220 IF ( t_psn_parentid ( p_index ) IS NULL ) THEN emit_dup (); END IF;
2221
2222 --Store in a hash and in a local variable.
2223
2224 copyto_local_variable ( l_id );
2225 hastore_def ( p_index );
2226 END emit_model_def;
2227 ---------------------------------------------------------------------------------------
2228 PROCEDURE emit_effectivity ( p_classname IN VARCHAR2
2229 , p_eff_from IN DATE
2230 , p_eff_until IN DATE
2231 , p_eff_usages IN VARCHAR2
2232 ) IS
2233
2234 l_eff_from DATE := NVL ( p_eff_from, const_epoch_begin );
2235 l_eff_until DATE := NVL ( p_eff_until, const_epoch_end );
2236 l_eff_usages VARCHAR2(16) := LPAD ( p_eff_usages, 16, '0');
2237
2238 BEGIN
2239
2240 IF ( l_eff_from > const_epoch_begin ) THEN
2241
2242 emit_dup ();
2243 push_date_constant ( l_eff_from );
2244
2245 emit_invokevirtual ( p_classname || '.setEffectiveFrom(Date)');
2246 emit_pop ( 1 );
2247
2248 END IF;
2249
2250 IF ( l_eff_until < const_epoch_end ) THEN
2251
2252 emit_dup ();
2253 push_date_constant ( l_eff_until );
2254
2255 emit_invokevirtual ( p_classname || '.setEffectiveUntil(Date)');
2256 emit_pop ( 1 );
2257
2258 END IF;
2259
2260 IF ( l_eff_usages <> const_mask_all_usages ) THEN
2261
2262 emit_dup ();
2263 push_mask_constant ( p_eff_usages );
2264
2265 emit_invokevirtual ( p_classname || '.setEffectiveUsages(long)');
2266 emit_pop ( 1 );
2267
2268 END IF;
2269 END emit_effectivity;
2270 ---------------------------------------------------------------------------------------
2271 -- Scope: compile_logic_file
2272 PROCEDURE emit_domainorder ( p_index IN PLS_INTEGER ) IS
2273 BEGIN
2274
2275 --This handles NULL correctly: NULL <> 0 is false, nothing will be generated.
2276
2277 IF ( t_psn_domainorder ( p_index ) <> 0) THEN
2278
2279 --This method is called on a variable right after the variable is created, so the variable
2280 --is on the stack. Need to 'dup' because after calling this method the variable will again
2281 --be either haloaded or popped.
2282
2283 emit_dup ();
2284
2285 emit_invokevirtual (
2286 CASE t_psn_domainorder ( p_index )
2287 WHEN const_domainorder_minfirst THEN 'IIntExprDef.setDomOrderMinFirst()'
2288 WHEN const_domainorder_maxfirst THEN 'IIntExprDef.setDomOrderMaxFirst()'
2289 WHEN const_domainorder_decmax THEN 'IIntExprDef.setDomOrderDecMax()'
2290 WHEN const_domainorder_incmin THEN 'IIntExprDef.setDomOrderIncMin()'
2291 WHEN const_domainorder_preffalse THEN 'IIntExprDef.setDomOrderMinFirst()'
2292 WHEN const_domainorder_preftrue THEN 'IIntExprDef.setDomOrderMaxFirst()'
2293 END);
2294
2295 --Void methods push null, need to pop it from the stack.
2296
2297 emit_pop ( 1 );
2298 END IF;
2299 END emit_domainorder;
2300 ---------------------------------------------------------------------------------------
2301 PROCEDURE emit_setid ( p_index IN PLS_INTEGER ) IS
2302 BEGIN
2303
2304 emit_dup ();
2305 push_long_constant ( t_psn_persistentnodeid ( p_index ));
2306 emit_invokevirtual ('IExprDef.setId(long)');
2307
2308 --Remove the null object from stack after a void method.
2309
2310 emit_pop ( 1 );
2311
2312 END emit_setid;
2313 ---------------------------------------------------------------------------------------
2314 -- Scope: compile_logic_file
2315 PROCEDURE emit_logicvar ( p_index IN PLS_INTEGER ) IS
2316 BEGIN
2317
2318 aload_model_def ( t_psn_parentid (p_index));
2319 push_variable_name ( p_index );
2320
2321 emit_invokevirtual ('IModelDef.logicVar(String)');
2322 emit_domainorder ( p_index );
2323
2324 emit_effectivity ( 'ILogicExprDef', t_psn_effectivefrom ( p_index ), t_psn_effectiveuntil ( p_index ), t_psn_effectiveusagemask ( p_index ));
2325
2326 emit_setid ( p_index );
2327 hastore_var ( p_index );
2328 END emit_logicvar;
2329 ---------------------------------------------------------------------------------------
2330 -- Scope: compile_logic_file
2331 PROCEDURE emit_intvar ( p_index IN PLS_INTEGER
2332 , p_min IN NUMBER
2333 , p_max IN NUMBER
2334 ) IS
2335
2336 l_ptr PLS_INTEGER;
2337
2338 BEGIN
2339
2340 aload_model_def ( t_psn_parentid (p_index));
2341 push_variable_name ( p_index );
2342
2343 push_integer_constant ( p_min );
2344 push_integer_constant ( p_max );
2345
2346 emit_invokevirtual ('IModelDef.intVar(String, int, int)');
2347 emit_domainorder ( p_index );
2348
2349 emit_setid ( p_index );
2350 hastore_var ( p_index );
2351 END emit_intvar;
2352 ---------------------------------------------------------------------------------------
2353 -- Scope: compile_logic_file
2354 PROCEDURE emit_floatvar ( p_index IN PLS_INTEGER
2355 , p_min IN NUMBER
2356 , p_max IN NUMBER
2357 ) IS
2358 BEGIN
2359
2360 aload_model_def ( t_psn_parentid (p_index));
2361 push_variable_name ( p_index );
2362
2363 --Null values should not be allowed.
2364
2365 push_double_constant ( p_min );
2366 push_double_constant ( p_max );
2367
2368 emit_invokevirtual ('IModelDef.floatVar(String, double, double)');
2369 emit_domainorder ( p_index );
2370
2371 emit_setid ( p_index );
2372 hastore_var ( p_index );
2373 END emit_floatvar;
2374 ---------------------------------------------------------------------------------------
2375 -- Scope: compile_logic_file
2376 --This procedure pushes on the stack the parent's object and the current variable
2377 --name. It is called for a feature to put the first two parameters of the feature
2378 --method on the stack before the options array.
2379 -- Scope: compile_logic_file
2380 PROCEDURE prepare_feature ( p_index IN PLS_INTEGER) IS
2381 BEGIN
2382
2383 aload_model_def ( t_psn_parentid (p_index));
2384 push_variable_name ( p_index );
2385
2386 END prepare_feature;
2387 ---------------------------------------------------------------------------------------
2388 -- Scope: compile_logic_file
2389 PROCEDURE emit_bagvar( p_index IN PLS_INTEGER
2390 , p_option_count IN PLS_INTEGER
2391 , p_cardmin IN NUMBER
2392 , p_cardmax IN NUMBER
2393 , p_countmin IN NUMBER
2394 , p_countmax IN NUMBER
2395 , p_max_option_qty IN NUMBER
2396 ) IS
2397 BEGIN
2398
2399 create_array ( p_option_count, h_javatypes('Object'));
2400 populate_array ( p_option_count );
2401 push_integer_constant ( p_cardmin );
2402 push_integer_constant ( p_cardmax );
2403 push_integer_constant ( p_countmin );
2404 push_integer_constant ( p_countmax );
2405 push_integer_constant ( p_max_option_qty );
2406
2407 emit_invokevirtual ('IModelDef.bagVar(String, Object[], int, int, int, int, int)');
2408 emit_effectivity ( 'ISetExprDef', t_psn_effectivefrom ( p_index ), t_psn_effectiveuntil ( p_index ), t_psn_effectiveusagemask ( p_index ));
2409
2410 emit_setid ( p_index );
2411 hastore_var ( p_index );
2412 END emit_bagvar;
2413 ---------------------------------------------------------------------------------------
2414 -- Scope: compile_logic_file
2415 PROCEDURE emit_setvar( p_index IN PLS_INTEGER
2416 , p_option_count IN PLS_INTEGER
2417 , p_cardmin IN NUMBER
2418 , p_cardmax IN NUMBER
2419 ) IS
2420 BEGIN
2421
2422 create_array ( p_option_count, h_javatypes('Object'));
2423 populate_array ( p_option_count );
2424 push_integer_constant ( p_cardmin );
2425 push_integer_constant ( p_cardmax );
2426
2427 emit_invokevirtual ('IModelDef.setVar(String, Object[], int, int)');
2428 emit_effectivity ( 'ISetExprDef', t_psn_effectivefrom ( p_index ), t_psn_effectiveuntil ( p_index ), t_psn_effectiveusagemask ( p_index ));
2429
2430 emit_setid ( p_index );
2431 hastore_var ( p_index );
2432 END emit_setvar;
2433 ---------------------------------------------------------------------------------------
2434 -- Scope: compile_logic_file
2435 PROCEDURE emit_singletonvar( p_index IN PLS_INTEGER ) IS
2436
2437 l_id NUMBER := t_psn_psnodeid ( p_index );
2438
2439 BEGIN
2440
2441 aload_model_def ( t_psn_parentid (p_index));
2442 push_variable_name ( p_index );
2443 aload_model_def ( l_id );
2444 emit_invokevirtual ('IModelDef.singletonVar(String, IModelDef)');
2445
2446 emit_setid ( p_index );
2447 hastore_var ( p_index );
2448 END emit_singletonvar;
2449 ---------------------------------------------------------------------------------------
2450 -- Scope: compile_logic_file
2451 PROCEDURE emit_instancesetvar( p_index IN PLS_INTEGER
2452 , p_cardmin IN NUMBER
2453 , p_cardmax IN NUMBER
2454 ) IS
2455 BEGIN
2456
2457 aload_model_def ( t_psn_parentid (p_index));
2458 push_variable_name ( p_index );
2459
2460 --#<dio integration>
2461 --A call to DIO will be made to retrieve the model def of the referenced model. The
2462 --referenced model is uniquely identified by the reference's persistent_node_id
2463 --within the context of the referencing model.
2464
2465 aload_model_def ( t_psn_psnodeid (p_index));
2466 push_integer_constant ( p_cardmin );
2467 push_integer_constant ( p_cardmax );
2468
2469 emit_invokevirtual ('IModelDef.instanceSetVar(String, IModelDef, int, int)');
2470 emit_effectivity ( 'IPortExprDef', t_psn_effectivefrom ( p_index ), t_psn_effectiveuntil ( p_index ), t_psn_effectiveusagemask ( p_index ));
2471
2472 emit_setid ( p_index );
2473
2474 --Variables can be only referenced in rule or port logic files, so there is
2475 --no need to store them in a local variable.
2476
2477 hastore_var ( p_index );
2478 END emit_instancesetvar;
2479 ---------------------------------------------------------------------------------------
2480 -- Scope: compile_logic_file
2481 PROCEDURE emit_connectorsetvar( p_index IN PLS_INTEGER
2482 , p_cardmin IN NUMBER
2483 , p_cardmax IN NUMBER
2484 ) IS
2485 BEGIN
2486
2487 aload_model_def ( t_psn_parentid (p_index));
2488 push_variable_name ( p_index );
2489
2490 --#<dio integration>
2491 --A call to DIO will be made to retrieve the model def of the referenced model. The
2492 --referenced model is uniquely identified by the reference's persistent_node_id
2493 --within the context of the referencing model.
2494
2495 aload_model_def ( t_psn_psnodeid (p_index));
2496 push_integer_constant ( p_cardmin );
2497 push_integer_constant ( p_cardmax );
2498
2499 emit_invokevirtual ('IModelDef.connectorSetVar(String, IModelDef, int, int)');
2500 emit_effectivity ( 'IPortExprDef', t_psn_effectivefrom ( p_index ), t_psn_effectiveuntil ( p_index ), t_psn_effectiveusagemask ( p_index ));
2501
2502 emit_setid ( p_index );
2503 hastore_var ( p_index );
2504 END emit_connectorsetvar;
2505 ---------------------------------------------------------------------------------------
2506 -- Scope: compile_logic_file
2507 PROCEDURE emit_bommodel_def ( p_index IN PLS_INTEGER
2508 , p_decimal_flag IN VARCHAR2
2509 ) IS
2510
2511 l_id NUMBER := t_psn_psnodeid ( p_index );
2512
2513 BEGIN
2514
2515 push_modeldef_name ( p_index );
2516 emit_boolean ( p_decimal_flag );
2517 emit_invokestatic ('Solver.createBomModelDef(String, boolean)');
2518
2519 --If this is the root model, save the model def on stack to be returned at the end.
2520
2521 IF ( t_psn_parentid ( p_index ) IS NULL) THEN emit_dup (); END IF;
2522
2523 --Store in a hash and in a local variable.
2524
2525 copyto_local_variable ( l_id );
2526 hastore_def ( p_index );
2527 END emit_bommodel_def;
2528 ---------------------------------------------------------------------------------------
2529 -- Scope: compile_logic_file
2530 PROCEDURE emit_bomoptionclass_def ( p_index IN PLS_INTEGER
2531 , p_decimal_flag IN VARCHAR2
2532 ) IS
2533
2534 l_id NUMBER := t_psn_psnodeid ( p_index );
2535
2536 BEGIN
2537
2538 push_variable_name ( p_index );
2539 emit_boolean ( p_decimal_flag );
2540 emit_invokestatic ('Solver.createBomOCDef(String, boolean)');
2541
2542 --Option class definition is used to create the child standard items, and also the
2543 --option class variable. Those will be always in the same file, and access the def
2544 --via a local variable.
2545
2546 --Also need to hastore, because if there is a reference to another bom model under
2547 --this option class, the bomModelVar will be called on this object in a different
2548 --logic file.
2549
2550 copyto_local_variable ( l_id );
2551 hastore_def ( p_index );
2552 END emit_bomoptionclass_def;
2553 ---------------------------------------------------------------------------------------
2554 -- Scope: compile_logic_file
2555 PROCEDURE emit_bommodelvar ( p_index IN PLS_INTEGER
2556 , p_decimal_flag IN VARCHAR2
2557 , p_required_flag IN VARCHAR2
2558 , p_min_qty IN NUMBER
2559 , p_max_qty IN NUMBER
2560 , p_def_qty IN NUMBER
2561 , p_cardmin IN NUMBER
2562 , p_cardmax IN NUMBER
2563 , p_eff_from IN DATE
2564 , p_eff_until IN DATE
2565 , p_eff_mask IN VARCHAR2
2566 ) IS
2567 BEGIN
2568
2569 aload_model_def ( t_psn_parentid ( p_index ));
2570 push_variable_name ( p_index );
2571
2572 --#<dio integration>
2573 --A call to DIO will be made to retrieve the model def of the referenced model. The
2574 --referenced model is uniquely identified by the reference's persistent_node_id
2575 --within the context of the referencing model.
2576
2577 aload_model_def ( t_psn_psnodeid ( p_index ));
2578 emit_boolean ( p_required_flag );
2579
2580 IF ( p_decimal_flag = '0') THEN
2581
2582 push_integer_constant ( p_min_qty );
2583 push_integer_constant ( p_max_qty );
2584 push_integer_constant ( p_def_qty );
2585 push_integer_constant ( p_cardmin );
2586 push_integer_constant ( p_cardmax );
2587
2588 ELSE
2589
2590 push_double_constant ( p_min_qty );
2591 push_double_constant ( p_max_qty );
2592 push_double_constant ( p_def_qty );
2593 push_double_constant ( p_cardmin );
2594 push_double_constant ( p_cardmax );
2595
2596 END IF;
2597
2598 push_date_constant ( p_eff_from );
2599 push_date_constant ( p_eff_until );
2600 push_mask_constant ( p_eff_mask );
2601
2602 IF ( p_decimal_flag = '0' ) THEN
2603
2604 emit_invokevirtual ('IModelDef.bomModelVar(String, IBomModelDef, boolean, int, int, int, int, int, Date, Date, long)');
2605
2606 ELSE
2607
2608 emit_invokevirtual ('IModelDef.bomModelVar(String, IBomModelDef, boolean, double, double, double, int, int, Date, Date, long)');
2609
2610 END IF;
2611
2612 emit_setid ( p_index );
2613 hastore_var ( p_index );
2614 END emit_bommodelvar;
2615 ---------------------------------------------------------------------------------------
2616 -- Scope: compile_logic_file
2617 PROCEDURE emit_bomoptionclassvar ( p_index IN PLS_INTEGER
2618 , p_decimal_flag IN VARCHAR2
2619 , p_required_flag IN VARCHAR2
2620 , p_min_qty IN NUMBER
2621 , p_max_qty IN NUMBER
2622 , p_def_qty IN NUMBER
2623 , p_minselected IN NUMBER
2624 , p_maxselected IN NUMBER
2625 , p_eff_from IN DATE
2626 , p_eff_until IN DATE
2627 , p_eff_mask IN VARCHAR2
2628 ) IS
2629
2630 l_id NUMBER := t_psn_psnodeid ( p_index );
2631
2632 BEGIN
2633
2634 --Is there a reason not to use local variable here?
2635
2636 aload_model_def ( t_psn_parentid (p_index));
2637 push_variable_name ( p_index );
2638 aload_model_def ( l_id );
2639 emit_boolean ( p_required_flag );
2640
2641 IF ( p_decimal_flag = '0' ) THEN
2642
2643 push_integer_constant ( p_min_qty );
2644 push_integer_constant ( p_max_qty );
2645 push_integer_constant ( p_def_qty );
2646 push_integer_constant ( p_minselected );
2647 push_integer_constant ( p_maxselected );
2648
2649 ELSE
2650
2651 push_double_constant ( p_min_qty );
2652 push_double_constant ( p_max_qty );
2653 push_double_constant ( p_def_qty );
2654 push_double_constant ( p_minselected );
2655 push_double_constant ( p_maxselected );
2656
2657 END IF;
2658
2659 push_date_constant ( p_eff_from );
2660 push_date_constant ( p_eff_until );
2661 push_mask_constant ( p_eff_mask );
2662
2663 IF ( p_decimal_flag = '0') THEN
2664
2665 emit_invokevirtual ('IBomDef.bomOptionClassVar(String, IBomOCDef, boolean, int, int, int, int, int, Date, Date, long)');
2666
2667 ELSE
2668
2669 emit_invokevirtual ('IBomDef.bomOptionClassVar(String, IBomOCDef, boolean, double, double, double, int, int, Date, Date, long)');
2670
2671 END IF;
2672
2673 emit_setid ( p_index );
2674 hastore_var ( p_index );
2675 END emit_bomoptionclassvar;
2676 ---------------------------------------------------------------------------------------
2677 -- Scope: compile_logic_file
2678 PROCEDURE emit_bomstandarditemvar ( p_index IN PLS_INTEGER
2679 , p_decimal_flag IN VARCHAR2
2680 , p_required_flag IN VARCHAR2
2681 , p_min_qty IN NUMBER
2682 , p_max_qty IN NUMBER
2683 , p_def_qty IN NUMBER
2684 , p_eff_from IN DATE
2685 , p_eff_until IN DATE
2686 , p_eff_mask IN VARCHAR2
2687 ) IS
2688 BEGIN
2689
2690 --Is there a reason not to use local variable here?
2691
2692 aload_model_def ( t_psn_parentid (p_index));
2693 push_variable_name ( p_index );
2694 emit_boolean ( p_required_flag );
2695
2696 IF ( p_decimal_flag = '0' ) THEN
2697
2698 push_integer_constant ( p_min_qty );
2699 push_integer_constant ( p_max_qty );
2700 push_integer_constant ( p_def_qty );
2701
2702 ELSE
2703
2704 push_double_constant ( p_min_qty );
2705 push_double_constant ( p_max_qty );
2706 push_double_constant ( p_def_qty );
2707
2708 END IF;
2709
2710 push_date_constant ( p_eff_from );
2711 push_date_constant ( p_eff_until );
2712 push_mask_constant ( p_eff_mask );
2713
2714 IF ( p_decimal_flag = '0' ) THEN
2715
2716 emit_invokevirtual ('IBomDef.bomStandardItemVar(String, boolean, int, int, int, Date, Date, long)');
2717
2718 ELSE
2719
2720 emit_invokevirtual ('IBomDef.bomStandardItemVar(String, boolean, double, double, double, Date, Date, long)');
2721
2722 END IF;
2723
2724 emit_setid ( p_index );
2725 hastore_var ( p_index );
2726 END emit_bomstandarditemvar;
2727 ---------------------------------------------------------------------------------------
2728 -- Scope: compile_logic_file
2729 PROCEDURE emit_reverseport ( p_index IN PLS_INTEGER) IS
2730 BEGIN
2731
2732 --This is a local variable. This only works if this port is a direct child of its own root.
2733
2734 haload_object ( t_psn_psnodeid (p_index), 1 );
2735
2736 --This is a remote variable in a direct child model. This only works if this port is
2737 --a direct child of its own root.
2738
2739 push_variable_name ( t_psn_reverseportid (p_index));
2740 haload2_object ( t_psn_persistentnodeid (p_index));
2741
2742 emit_invokevirtual ('IPortExprDef.setReversePort(IPortExprDef)');
2743
2744 --#<optimization-reverseport>:Void methods push null, need to pop it from the stack.
2745 --We do not pop it here in order to implement optimization.
2746 END emit_reverseport;
2747 ---------------------------------------------------------------------------------------
2748 -- Scope: compile_logic_file
2749 PROCEDURE create_feature ( p_index IN PLS_INTEGER
2750 , p_option_count IN PLS_INTEGER
2751 , p_var_min IN NUMBER
2752 , p_var_max IN NUMBER
2753 , p_var_count IN NUMBER
2754 ) IS
2755 BEGIN
2756
2757 CASE t_psn_countedoptionsflag ( p_index )
2758
2759 WHEN '1' THEN
2760
2761 IF ( p_var_count = 0 ) THEN
2762
2763 report_and_raise_sys_error(
2764 p_message => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SE_OPTION_MAXQ_NOT_ZERO,
2765 'NODE_NAME', CZ_FCE_COMPILE_UTILS.GET_NODE_PATH (
2766 t_psn_psnodeid ( p_index ),
2767 ps_node_id_table_to_string(
2768 build_model_path(t_psn_psnodeid ( p_index )) ) ) ),
2769 p_run_id => x_run_id,
2770 p_model_id => p_component_id
2771 );
2772
2773 END IF;
2774
2775 emit_bagvar( p_index
2776 , p_option_count
2777 , p_var_min
2778 , p_var_max * p_var_count
2779 , p_var_min
2780 , p_var_max
2781 , p_var_count
2782 );
2783
2784 ELSE
2785
2786 emit_setvar( p_index
2787 , p_option_count
2788 , p_var_min
2789 , p_var_max
2790 );
2791
2792 END CASE;
2793 END create_feature;
2794 ---------------------------------------------------------------------------------------
2795 ---------------------------------------------------------------------------------------
2796 ---------------------------------------------------------------------------------------
2797 -- Scope: compile_logic_file
2798 FUNCTION is_bom_port ( p_index IN PLS_INTEGER ) RETURN BOOLEAN IS
2799 BEGIN
2800
2801 RETURN t_psn_psnodetype ( p_index ) IN ( h_psntypes ('reference'), h_psntypes ('connector')) AND
2802 h_psnid_psnodetype ( TO_CHAR ( t_psn_referenceid ( p_index ))) =
2803 h_psntypes ('bommodel');
2804
2805 END is_bom_port;
2806 ---------------------------------------------------------------------------------------
2807 -- Scope: compile_logic_file
2808 FUNCTION is_bom_node ( p_index IN PLS_INTEGER ) RETURN BOOLEAN IS
2809 BEGIN
2810
2811 RETURN t_psn_psnodetype ( p_index ) IN ( h_psntypes ('bomoptionclass'), h_psntypes ('bommodel'), h_psntypes ('bomstandard'));
2812
2813 END is_bom_node;
2814 ---------------------------------------------------------------------------------------
2815 -- Scope: compile_logic_file
2816 FUNCTION is_bom ( p_index IN PLS_INTEGER ) RETURN BOOLEAN IS
2817 BEGIN
2818
2819 RETURN is_bom_node ( p_index ) OR is_bom_port ( p_index );
2820
2821 END is_bom;
2822 ---------------------------------------------------------------------------------------
2823 ---------------------------------------------------------------------------------------
2824 ---------------------------------------------------------------------------------------
2825 -- Scope: compile_logic_file
2826 PROCEDURE compile_constraints IS
2827
2828 t_expl_modelrefexplid type_number_table;
2829 t_expl_parentexplnodeid type_number_table;
2830 t_expl_componentid type_number_table;
2831 t_expl_referringnodeid type_number_table;
2832 t_expl_explnodetype type_number_table;
2833
2834 h_explid_backindex type_data_hashtable;
2835 h_parentid_referring_explid type_nodehashtable_hashtable;
2836
2837 t_exp_modelrefexplid type_number_table;
2838 t_exp_exprtype type_number_table;
2839 t_exp_exprnodeid type_number_table;
2840 t_exp_exprparentid type_number_table;
2841 t_exp_templateid type_number_table;
2842 t_exp_psnodeid type_number_table;
2843 t_exp_datavalue type_varchar4000_table;
2844 t_exp_propertyid type_number_table;
2845 t_exp_paramindex type_number_table;
2846 t_exp_argumentindex type_number_table;
2847 t_exp_argumentname type_varchar4000_table;
2848 t_exp_datatype type_number_table;
2849 t_exp_datanumvalue type_number_table;
2850 t_exp_paramsignatureid type_number_table;
2851 t_exp_relativenodepath type_varchar4000_table;
2852 t_exp_seqnbr type_number_table;
2853
2854 h_exprid_childrenindex type_data_hashtable;
2855 h_exprid_backindex type_data_hashtable;
2856 h_exprid_numberofchildren type_data_hashtable;
2857 t_instancequantifiers type_varchar4000_table;
2858 h_instancequantifiers type_data_hashtable;
2859
2860 h_propertyid_datatype type_node_hashtable;
2861 h_propertyid_type type_node_hashtable;
2862 h_propertyid_defvalue type_name_hashtable;
2863 h_psnid_propertyid_value type_name_hashtable;
2864
2865 t_acc_complete_path type_numbertable_table;
2866 t_acc_targets type_varchar4000_table;
2867 t_acc_target_sequence type_integer_table;
2868 t_acc_local_quantifiers type_varchar4000_table;
2869 t_acc_contributors type_contributortable_table;
2870 t_acc_quantifiers type_varchar4000table_table;
2871 h_acc_targets type_data_hashtable;
2872 h_acc_quantifiers type_datahashtable_table;
2873 t_target_quantifiers type_varchar4000table_table;
2874 h_target_quantifiers type_datahashtable_table;
2875
2876 h_parameter_stack type_iteratorhashtable_table;
2877 t_argument_table type_integertable_table;
2878
2879 l_rule_expr_lastindex PLS_INTEGER;
2880 l_input_context expression_context;
2881 l_output_context expression_context;
2882
2883 this_rule_id NUMBER;
2884 this_reason_id NUMBER;
2885 this_rule_class NUMBER;
2886 this_rule_name VARCHAR2(255);
2887 this_effective_from DATE;
2888 this_effective_until DATE;
2889 this_effective_usages VARCHAR2(16);
2890
2891 l_key VARCHAR2(4000);
2892 l_count PLS_INTEGER;
2893 l_run_id NUMBER;
2894
2895 assistant_var_id PLS_INTEGER := 0;
2896 target_count_svp PLS_INTEGER;
2897
2898 contributor_validation PLS_INTEGER;
2899
2900 ----------------------------------------------------------------------------------
2901 -- This procedure reports user rule warning and by default raises
2902 -- CZ_LOGICGEN_WARNING exception. Optional p_warning_location can be
2903 -- specified to record the code location of the warning (like method where
2904 -- the warning occurred). Warning location is stored in the error_stack column
2905 -- of the cz_db_logs table.
2906 -- Scope: compile_constraints
2907 PROCEDURE report_and_raise_rule_warning (
2908 p_text IN VARCHAR2,
2909 p_warning_location IN VARCHAR2 DEFAULT NULL ) IS
2910
2911 BEGIN
2912 report_and_raise_warning(
2913 p_message => p_text,
2914 p_run_id => x_run_id,
2915 p_model_id => p_component_id,
2916 p_ps_node_id => NULL,
2917 p_rule_id => this_rule_id,
2918 p_error_stack => p_warning_location
2919 );
2920 END report_and_raise_rule_warning;
2921
2922 -- This procedure reports user rule warning and by default raises
2923 -- CZ_LOGICGEN_WARNING exception. This procedure substitutes the rule_name
2924 -- and model_name parameters in the given message. Optional p_warning_location can be
2925 -- specified to record the code location of the warning (like method where
2926 -- the warning occurred). Warning location is stored in the error_stack column
2927 -- of the cz_db_logs table.
2928 -- Scope: compile_constraints
2929 PROCEDURE report_and_raise_rule_sys_warn (
2930 p_text IN VARCHAR2,
2931 p_warning_location IN VARCHAR2 DEFAULT NULL ) IS
2932
2933 BEGIN
2934
2935 report_and_raise_sys_warning(
2936 p_message => GET_NOT_TRANSLATED_TEXT(
2937 p_text,
2938 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
2939 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
2940 p_run_id => x_run_id,
2941 p_model_id => p_component_id,
2942 p_ps_node_id => NULL,
2943 p_rule_id => this_rule_id,
2944 p_error_stack => p_warning_location
2945 );
2946 END report_and_raise_rule_sys_warn;
2947
2948 ----------------------------------------------------------------------------------
2949 -- Scope: compile_constraints
2950 FUNCTION build_reference_path ( p_expl_id IN NUMBER ) RETURN type_number_table IS
2951
2952 l_expl_id VARCHAR2(4000) := TO_CHAR ( p_expl_id );
2953 l_key VARCHAR2(4000);
2954 l_index PLS_INTEGER;
2955 tl_id_path type_number_table;
2956
2957 BEGIN
2958
2959 IF ( h_explid_referencepath.EXISTS ( l_expl_id )) THEN RETURN h_explid_referencepath ( l_expl_id ); END IF;
2960
2961 l_key := l_expl_id;
2962
2963 BEGIN
2964
2965 WHILE ( l_expl_id IS NOT NULL ) LOOP
2966
2967 l_index := h_explid_backindex ( l_expl_id );
2968
2969 IF ( t_expl_referringnodeid ( l_index ) IS NOT NULL ) THEN
2970
2971 --This is a reference or connector.
2972
2973 tl_id_path ( tl_id_path.COUNT + 1 ) := t_expl_referringnodeid ( l_index );
2974
2975 END IF;
2976
2977 l_expl_id := TO_CHAR ( t_expl_parentexplnodeid ( l_index ));
2978 END LOOP;
2979
2980 EXCEPTION
2981 WHEN OTHERS THEN
2982
2983 --#<should never happen>
2984 report_and_raise_rule_sys_warn(
2985 GET_NOT_TRANSLATED_TEXT(
2986 CZ_FCE_SW_INCORRECT_EXPL_ID,
2987 'EXPLOSION_ID', l_expl_id),
2988 p_warning_location => 'build_reference_path');
2989 END;
2990
2991 h_explid_referencepath ( l_key ) := tl_id_path;
2992
2993 RETURN tl_id_path;
2994 END build_reference_path;
2995 ----------------------------------------------------------------------------------
2996 -- Scope: compile_constraints
2997 FUNCTION build_complete_path ( p_node_id IN NUMBER, p_expl_id IN NUMBER ) RETURN type_number_table IS
2998
2999 tl_complete_path type_number_table;
3000 tl_reference_path type_number_table;
3001 tl_model_path type_number_table;
3002
3003 l_key VARCHAR2(4000);
3004 l_start PLS_INTEGER := 1;
3005
3006 BEGIN
3007
3008 l_key := TO_CHAR ( p_node_id ) || '_' || TO_CHAR ( p_expl_id );
3009 IF ( h_psnid_explid_completepath.EXISTS ( l_key )) THEN RETURN h_psnid_explid_completepath ( l_key ); END IF;
3010
3011 tl_complete_path := build_model_path ( p_node_id );
3012 tl_reference_path := build_reference_path ( p_expl_id );
3013
3014 IF ( tl_reference_path.COUNT = 0 ) THEN
3015
3016 h_psnid_explid_completepath ( l_key ) := tl_complete_path;
3017 RETURN tl_complete_path;
3018
3019 END IF;
3020
3021 IF ( h_psnid_psnodetype ( TO_CHAR ( p_node_id )) IN ( h_psntypes ('reference'), h_psntypes ('connector'))) THEN
3022
3023 --If the node is a reference or connector itself, we need to cut off its own explosion,
3024 --which is the first element because the array is populated bottom up.
3025
3026 l_start := 2;
3027
3028 END IF;
3029
3030 FOR i IN l_start..tl_reference_path.COUNT LOOP
3031
3032 tl_model_path := build_model_path ( tl_reference_path ( i ));
3033
3034 FOR ii IN 1..tl_model_path.COUNT LOOP
3035
3036 tl_complete_path ( tl_complete_path.COUNT + 1 ) := tl_model_path ( ii );
3037
3038 END LOOP;
3039 END LOOP;
3040
3041 h_psnid_explid_completepath ( l_key ) := tl_complete_path;
3042
3043 RETURN tl_complete_path;
3044 END build_complete_path;
3045 ----------------------------------------------------------------------------------
3046 -- Scope: compile_constraints
3047 PROCEDURE generate_expression ( j IN PLS_INTEGER
3048 , p_input_context IN expression_context
3049 , x_output_context IN OUT NOCOPY expression_context );
3050 ----------------------------------------------------------------------------------
3051 -- Scope: compile_constraints
3052 PROCEDURE set_rule_savepoint IS
3053 BEGIN
3054
3055 set_savepoint ();
3056 target_count_svp := t_acc_targets.COUNT;
3057
3058 END set_rule_savepoint;
3059 ----------------------------------------------------------------------------------
3060 -- Scope: compile_constraints
3061 PROCEDURE restore_rule_savepoint IS
3062 BEGIN
3063
3064 restore_savepoint ();
3065 t_acc_targets.DELETE ( target_count_svp + 1, t_acc_targets.COUNT );
3066
3067 END restore_rule_savepoint;
3068 ----------------------------------------------------------------------------------
3069 -- Scope: compile_logic_file
3070 PROCEDURE sum_numeric ( p_count IN PLS_INTEGER ) IS
3071 BEGIN
3072
3073 IF ( p_count = 2 ) THEN
3074
3075 --There are two distinct values, use addition instead of sum.
3076
3077 emit_invokevirtual ('INumExprDef.sum(INumExprDef)');
3078
3079 ELSIF ( p_count > 2 ) THEN
3080
3081 --In general case create an array of parameters and call IModelDef.sum. The model def
3082 --for that should already be on stack.
3083
3084 create_array ( p_count, h_javatypes ('INumExprDef'));
3085 populate_array ( p_count );
3086 emit_invokevirtual ('IModelDef.sum(INumExprDef[])');
3087
3088 END IF;
3089 END sum_numeric;
3090 ----------------------------------------------------------------------------------
3091 -- Scope: compile_constraints
3092 PROCEDURE clear_argument_table IS
3093 BEGIN
3094
3095 IF ( t_argument_table.EXISTS ( h_parameter_stack.COUNT )) THEN
3096
3097 t_argument_table ( h_parameter_stack.COUNT ).DELETE;
3098
3099 END IF;
3100 END clear_argument_table;
3101 ----------------------------------------------------------------------------------
3102 -- Scope: compile_constraints
3103 PROCEDURE add_argument ( j IN PLS_INTEGER ) IS
3104
3105 l_count PLS_INTEGER := 1;
3106
3107 BEGIN
3108
3109 IF ( t_argument_table.EXISTS ( h_parameter_stack.COUNT )) THEN
3110
3111 l_count := t_argument_table ( h_parameter_stack.COUNT ).COUNT + 1;
3112
3113 END IF;
3114
3115 t_argument_table ( h_parameter_stack.COUNT )( l_count ) := j;
3116
3117 END add_argument;
3118 ----------------------------------------------------------------------------------
3119 -- Scope: compile_constraints
3120 PROCEDURE restore_arguments IS
3121 BEGIN
3122
3123 IF ( t_argument_table.EXISTS ( h_parameter_stack.COUNT )) THEN
3124
3125 FOR i IN 1..t_argument_table ( h_parameter_stack.COUNT ).COUNT LOOP
3126
3127 t_exp_exprtype ( t_argument_table ( h_parameter_stack.COUNT )( i )) := h_exprtypes ('argument');
3128
3129 END LOOP;
3130 END IF;
3131 END restore_arguments;
3132 ----------------------------------------------------------------------------------
3133 -- Scope: compile_constraints
3134 FUNCTION retrieve_parameter ( p_name IN VARCHAR2 ) RETURN type_iterator_value IS
3135
3136 l_count PLS_INTEGER;
3137
3138 BEGIN
3139
3140 --When generating or looking up a parameter, it is always enough to look up only
3141 --on top of the stack. We only look up parameters during parsing of where clause
3142 --which happens before the forall, currently being generated, puts parameters on
3143 --the stack, so at this moment the parameter from the outer forall, which we are
3144 --looking up, should be on top of the stack.
3145
3146 l_count := h_parameter_stack.COUNT;
3147
3148 IF ( NOT h_parameter_stack ( l_count ).EXISTS ( p_name )) THEN
3149
3150 --#<should never happen>
3151 report_and_raise_rule_sys_warn (
3152 p_text => GET_NOT_TRANSLATED_TEXT (
3153 CZ_FCE_SW_NO_VALUE_PARAMSTK,
3154 'PARAM', p_name ),
3155 p_warning_location => 'retrieve_parameter' );
3156
3157 END IF;
3158
3159 RETURN h_parameter_stack ( l_count )( p_name );
3160
3161 END;
3162 ----------------------------------------------------------------------------------
3163 -- Scope: compile_constraints
3164 -- Returns TRUE when the given expression has children, otherwise returns FALSE.
3165 FUNCTION expr_has_children ( p_expr_id IN VARCHAR2 ) RETURN BOOLEAN IS
3166 BEGIN
3167 IF ( NOT h_exprid_childrenindex.EXISTS ( p_expr_id )) THEN
3168 RETURN FALSE;
3169 ELSE
3170 RETURN TRUE;
3171 END IF;
3172 END expr_has_children;
3173 ----------------------------------------------------------------------------------
3174 -- Scope: compile_constraints
3175 -- Returns TRUE when the given expression has only one child, otherwise returns FALSE.
3176 FUNCTION expr_has_one_child ( p_expr_id IN VARCHAR2 ) RETURN BOOLEAN IS
3177 BEGIN
3178 IF ( expr_has_children(p_expr_id) AND h_exprid_numberofchildren ( p_expr_id ) = 1) THEN
3179 RETURN TRUE;
3180 ELSE
3181 RETURN FALSE;
3182 END IF;
3183 END expr_has_one_child;
3184 ----------------------------------------------------------------------------------
3185 -- Scope: compile_constraints
3186 -- Returns TRUE when the given expression has only two child, otherwise returns FALSE.
3187 FUNCTION expr_has_two_children ( p_expr_id IN VARCHAR2 ) RETURN BOOLEAN IS
3188 BEGIN
3189 IF ( expr_has_children(p_expr_id) AND h_exprid_numberofchildren ( p_expr_id ) = 2) THEN
3190 RETURN TRUE;
3191 ELSE
3192 RETURN FALSE;
3193 END IF;
3194 END expr_has_two_children;
3195 ----------------------------------------------------------------------------------
3196 -- Scope: compile_constraints
3197 -- Returns the node details (using type_iterator_value structure)
3198 -- associated with the given line index. Returns type_iterator_value.value_type
3199 -- as null when the line index is not referrings to a node.
3200 FUNCTION get_structure_node ( p_index IN PLS_INTEGER ) RETURN type_iterator_value IS
3201
3202 l_parameter type_iterator_value;
3203
3204 BEGIN
3205
3206 l_parameter.value_type := const_valuetype_unknown;
3207
3208 IF ( t_exp_exprtype ( p_index ) = h_exprtypes ('node')) THEN
3209
3210 l_parameter.ps_node_id := t_exp_psnodeid ( p_index );
3211 l_parameter.model_ref_expl_id := t_exp_modelrefexplid ( p_index );
3212
3213 l_parameter.value_type := const_valuetype_node;
3214
3215 ELSIF ( t_exp_exprtype ( p_index ) = h_exprtypes ('argument')) THEN
3216
3217 l_parameter := retrieve_parameter ( t_exp_argumentname ( p_index ));
3218
3219 END IF;
3220
3221 IF ( l_parameter.value_type <> const_valuetype_node ) THEN
3222
3223 l_parameter.value_type := NULL;
3224
3225 END IF;
3226
3227 RETURN l_parameter;
3228 END get_structure_node;
3229 ----------------------------------------------------------------------------------
3230 -- Scope: compile_constraints
3231 -- Returns TRUE when the given node has children, otherwise returns FALSE.
3232 FUNCTION node_has_children ( p_node_id IN VARCHAR2 ) RETURN BOOLEAN IS
3233 BEGIN
3234 IF ( h_psnid_lastchildindex.EXISTS ( p_node_id )) THEN
3235 RETURN TRUE;
3236 ELSE
3237 RETURN FALSE;
3238 END IF;
3239 END node_has_children;
3240 ----------------------------------------------------------------------------------
3241 --This function verifies that a node is a port, and returns its target.
3242 -- Scope: compile_constraints
3243 -- Returns the target node id for the given port. Returns NULL when
3244 -- the given id is not a port.
3245 FUNCTION get_port_id ( p_node_id IN VARCHAR2 ) RETURN NUMBER IS
3246 l_index PLS_INTEGER := h_psnid_backindex ( p_node_id );
3247 BEGIN
3248 IF ( t_psn_detailedtype ( l_index ) IN ( h_psntypes ('reference'), h_psntypes ('connector'))) THEN
3249
3250 RETURN t_psn_referenceid ( l_index );
3251
3252 ELSIF ( t_psn_detailedtype ( l_index ) = h_psntypes ('component')) THEN
3253
3254 RETURN t_psn_psnodeid ( l_index );
3255
3256 ELSE
3257
3258 RETURN NULL;
3259 END IF;
3260 END get_port_id;
3261 ----------------------------------------------------------------------------------
3262 --This function is used to explode OptionOf or Options() operation into a table of
3263 --children for boms. Only bom children are included.
3264 -- Scope: compile_constraints
3265 FUNCTION explode_bom_children ( p_node_id IN NUMBER
3266 , p_expl_id IN NUMBER
3267 , p_first_index IN PLS_INTEGER
3268 , p_last_index IN PLS_INTEGER
3269 , p_optional_only IN BOOLEAN
3270 ) RETURN type_iteratornode_table IS
3271
3272 t_children type_iteratornode_table;
3273 l_expl_id VARCHAR2(4000);
3274
3275 l_index PLS_INTEGER;
3276 l_count PLS_INTEGER;
3277
3278 BEGIN
3279
3280 l_index := p_first_index;
3281 l_count := 1;
3282
3283 l_expl_id := TO_CHAR ( p_expl_id );
3284
3285 WHILE ( l_index <= p_last_index ) LOOP
3286
3287 IF ( t_psn_parentid ( l_index ) = p_node_id AND is_bom ( l_index ) AND
3288 ( NOT p_optional_only OR t_psn_bomrequiredflag ( l_index ) = '0' )) THEN
3289
3290 t_children ( l_count ).expr_index := l_index;
3291 t_children ( l_count ).ps_node_id := t_psn_psnodeid ( l_index );
3292
3293 IF ( t_psn_psnodetype ( l_index ) IN ( h_psntypes ('reference'), h_psntypes ('connector'))) THEN
3294
3295 --If the bom child is a reference, we need to adjust the explosion id to be that
3296 --of the reference.
3297
3298 t_children ( l_count ).model_ref_expl_id := h_parentid_referring_explid ( l_expl_id )( TO_CHAR ( t_psn_psnodeid ( l_index )));
3299
3300 ELSE
3301
3302 t_children ( l_count ).model_ref_expl_id := p_expl_id;
3303
3304 END IF;
3305
3306 l_count := l_count + 1;
3307
3308 END IF;
3309
3310 l_index := l_index + 1;
3311
3312 END LOOP;
3313
3314 IF ( t_children.COUNT = 0 ) THEN
3315
3316 -- BOM node ^NODE_NAME has no optional selections to participate in rule. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
3317
3318 report_and_raise_rule_warning (
3319 CZ_UTILS.GET_TEXT ( CZ_FCE_W_NO_OPTIONAL_CHILDREN,
3320 'NODE_NAME', CZ_FCE_COMPILE_UTILS.GET_NODE_PATH( p_node_id,
3321 ps_node_id_table_to_string(
3322 build_complete_path(p_node_id, p_expl_id) ) ),
3323 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name ),
3324 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name )),
3325 'explode_bom_children'
3326 );
3327
3328 END IF;
3329
3330 RETURN t_children;
3331 END explode_bom_children;
3332 ----------------------------------------------------------------------------------
3333 --This function is used to explode OptionOf or Options() operation into a table of
3334 --children.
3335 -- Scope: compile_constraints
3336 FUNCTION explode_node_children ( p_node_id IN NUMBER, p_expl_id IN NUMBER, p_optional_only IN BOOLEAN )
3337 RETURN type_iteratornode_table IS
3338
3339 t_children type_iteratornode_table;
3340 l_node_id VARCHAR2(4000);
3341
3342 l_last_index PLS_INTEGER;
3343 l_index PLS_INTEGER;
3344 l_count PLS_INTEGER;
3345
3346 BEGIN
3347
3348 l_node_id := TO_CHAR ( p_node_id );
3349 l_index := h_psnid_backindex ( l_node_id );
3350
3351 IF ( is_bom_port ( l_index )) THEN
3352
3353 l_node_id := TO_CHAR ( t_psn_referenceid ( l_index ));
3354 l_index := h_psnid_backindex ( l_node_id );
3355
3356 END IF;
3357
3358 -- Node ^NODE_NAME has no children. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
3359
3360 IF ( node_has_children ( l_node_id )) THEN
3361
3362 l_last_index := h_psnid_lastchildindex ( l_node_id );
3363
3364 ELSE
3365
3366 -- Node ^NODE_NAME has no children. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
3367
3368 report_and_raise_rule_warning (
3369 p_text => CZ_UTILS.GET_TEXT( CZ_FCE_W_NODE_MUST_HAVE_CHILD,
3370 'NODE_NAME', CZ_FCE_COMPILE_UTILS.GET_NODE_PATH( p_node_id,
3371 ps_node_id_table_to_string(
3372 build_complete_path(p_node_id, p_expl_id) ) ),
3373 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name ),
3374 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH ( p_component_id, p_model_path)
3375 ),
3376 p_warning_location => 'explode_node_children');
3377
3378 END IF;
3379
3380 IF ( is_bom_node ( l_index )) THEN
3381
3382 t_children := explode_bom_children ( l_node_id, p_expl_id, l_index + 1, l_last_index, p_optional_only );
3383
3384 ELSE
3385
3386 --If this is non-bom, the operation can only be performed on an option feature.
3387 --Options always follow the feature and there can be no tokens among them. The
3388 --explosion is always that of the feature.
3389
3390 l_index := l_index + 1;
3391 l_count := 1;
3392
3393 WHILE ( l_index <= l_last_index ) LOOP
3394
3395 t_children ( l_count ).expr_index := l_index;
3396 t_children ( l_count ).ps_node_id := t_psn_psnodeid ( l_index );
3397 t_children ( l_count ).model_ref_expl_id := p_expl_id;
3398
3399 l_count := l_count + 1;
3400 l_index := l_index + 1;
3401
3402 END LOOP;
3403 END IF;
3404
3405 RETURN t_children;
3406 END explode_node_children;
3407 ---------------------------------------------------------------------------------------
3408 --p_type is either 'ISingletonExprDef', 'IInstanceQuantifier' or 'IPortExprDef'.
3409 --It can also be NULL if the variable is local.
3410 -- Scope: compile_constraints
3411 PROCEDURE push_variable ( p_id IN NUMBER, p_type IN VARCHAR2 ) IS
3412
3413 l_id VARCHAR2(4000) := TO_CHAR ( p_id );
3414
3415 BEGIN
3416
3417 --This procedure can be called on a Bom Model, when a reference to this model
3418 --participates in rules.
3419
3420 IF ( h_psnid_psnodetype ( l_id ) = h_psntypes ('bommodel')) THEN RETURN; END IF;
3421
3422 IF ( h_psnid_devlprojectid ( l_id ) = p_component_id ) THEN
3423
3424 --This is a local variable, we can just retrieve it from the local hash.
3425
3426 haload_object ( p_id , 1 );
3427
3428 ELSE
3429
3430 --This is a remote variable. Need to duplicate parent's object on the stack
3431 --to be used for the call to getType().
3432
3433 emit_dup ();
3434 emit_invokevirtual ( p_type || '.getType()');
3435 push_variable_name ( p_id );
3436 emit_invokevirtual ('IModelDef.getVar(String)');
3437
3438 END IF;
3439 END push_variable;
3440 ----------------------------------------------------------------------------------
3441 --This function splits the '_'-separated path of ps_node_id(s) into a number table.
3442 -- Scope: compile_constraints
3443 FUNCTION split_path ( p_path IN VARCHAR2 ) RETURN type_number_table IS
3444
3445 l_substr VARCHAR2(32000) := p_path;
3446 l_index PLS_INTEGER;
3447 l_return_tbl type_number_table;
3448
3449 BEGIN
3450
3451 IF ( l_substr IS NULL )THEN RETURN l_return_tbl; END IF;
3452
3453 LOOP
3454
3455 l_index := INSTR ( l_substr, '_', -1 );
3456
3457 IF ( l_index > 0 ) THEN
3458
3459 l_return_tbl ( l_return_tbl.COUNT + 1 ) := TO_NUMBER ( SUBSTR ( l_substr, l_index + 1 ));
3460 l_substr := SUBSTR (l_substr, 1, l_index - 1 );
3461
3462 ELSE
3463
3464 l_return_tbl (l_return_tbl.COUNT + 1 ) := TO_NUMBER ( l_substr );
3465 EXIT;
3466
3467 END IF;
3468 END LOOP;
3469
3470 RETURN l_return_tbl;
3471 END split_path;
3472 ---------------------------------------------------------------------------------------
3473 FUNCTION split_str_path ( p_path IN VARCHAR2 ) RETURN type_varchar4000_table IS
3474
3475 l_substr VARCHAR2(32000) := p_path;
3476 l_index PLS_INTEGER;
3477 l_return_tbl type_varchar4000_table;
3478
3479 BEGIN
3480
3481 IF ( p_path IS NULL ) THEN RETURN l_return_tbl; END IF;
3482
3483 LOOP
3484
3485 l_index := INSTR ( l_substr, FND_GLOBAL.LOCAL_CHR ( 7 ));
3486
3487 IF( l_index > 0 )THEN
3488
3489 l_return_tbl (l_return_tbl.COUNT + 1 ) := SUBSTR ( l_substr, 1, l_index - 1 );
3490 l_substr := SUBSTR( l_substr, l_index + 1 );
3491
3492 ELSE
3493
3494 l_return_tbl (l_return_tbl.COUNT + 1 ) := l_substr;
3495 EXIT;
3496
3497 END IF;
3498 END LOOP;
3499
3500 RETURN l_return_tbl;
3501
3502 END split_str_path;
3503 ---------------------------------------------------------------------------------------
3504 -- Scope: compile_constraints
3505 FUNCTION generate_path ( p_complete_path IN type_number_table
3506 , p_input_context IN expression_context
3507 , x_output_context IN OUT NOCOPY expression_context
3508 ) RETURN PLS_INTEGER IS
3509
3510 tl_target_path type_number_table;
3511
3512 l_count PLS_INTEGER;
3513 l_quantifier_index PLS_INTEGER;
3514 l_instances_index PLS_INTEGER;
3515 l_target_index PLS_INTEGER;
3516 l_contrib_index PLS_INTEGER;
3517 l_singleton_count PLS_INTEGER;
3518 l_acc_count PLS_INTEGER;
3519 l_target_count PLS_INTEGER;
3520
3521 l_key VARCHAR2(4000);
3522 l_return PLS_INTEGER := const_no_instances;
3523
3524 BEGIN
3525
3526 IF ( p_input_context.context_type = const_context_target ) THEN
3527
3528 l_target_count := t_acc_targets.COUNT;
3529
3530 END IF;
3531
3532 --Find the most shallow port, it's instancesOf should be called on IModelDef.
3533
3534 l_count := p_complete_path.COUNT;
3535 l_instances_index := l_count;
3536
3537 WHILE ( l_instances_index > 0 AND h_psnid_detailedtype ( p_complete_path ( l_instances_index )) NOT IN
3538 ( h_psntypes ('component'), h_psntypes ('reference'), h_psntypes ('connector'))) LOOP
3539
3540 l_instances_index := l_instances_index - 1;
3541
3542 END LOOP;
3543
3544 IF ( l_instances_index <= l_count AND l_instances_index > 1 ) THEN
3545
3546 --We count the number of node participants in the contributor expression which are
3547 --under ports for validation. Participant itself can be the only port in the path,
3548 --this is allowed (l_instances_index > 1)
3549
3550 contributor_validation := contributor_validation + 1;
3551
3552 END IF;
3553
3554 IF ( p_input_context.context_type = const_context_contributor ) THEN
3555
3556 --We are generating an accumulation contributor. Need to find the LCA with the target's path,
3557 --because this will be the instance quantifier. Below this node we will generate hierarchical
3558 --unions.
3559
3560 --The target for this contributor is the last element in the array of target.
3561
3562 l_target_count := p_input_context.context_num_data;
3563 tl_target_path := t_acc_complete_path ( l_target_count );
3564
3565 --Find the LCA.
3566
3567 l_target_index := tl_target_path.COUNT;
3568 l_contrib_index := l_count;
3569 l_quantifier_index := l_contrib_index + 1;
3570
3571 IF ( l_target_index > 0 ) THEN
3572
3573 WHILE ( l_target_index > 0 AND l_contrib_index > 0 AND
3574 tl_target_path ( l_target_index ) = p_complete_path ( l_contrib_index )) LOOP
3575
3576 IF ( h_psnid_detailedtype ( p_complete_path ( l_contrib_index )) IN
3577 ( h_psntypes ('component'), h_psntypes ('reference'), h_psntypes ('connector'))) THEN
3578
3579 l_quantifier_index := l_contrib_index;
3580
3581 END IF;
3582
3583 l_target_index := l_target_index - 1;
3584 l_contrib_index := l_contrib_index - 1;
3585
3586 END LOOP;
3587 END IF;
3588
3589 ELSE
3590
3591 --Find the deepest port, this will be the instance quantifier to use in forAll.
3592
3593 l_quantifier_index := 2;
3594
3595 --#<important>
3596 --Using h_psnid_detailedtype is very essential here and in the next block. If any changes are made
3597 --to the definition of h_psnid_detailedtype array, this code may need to change.
3598
3599 WHILE ( l_quantifier_index <= l_count AND h_psnid_detailedtype ( p_complete_path ( l_quantifier_index )) NOT IN
3600 (h_psntypes ('component'), h_psntypes ('reference'), h_psntypes ('connector'))) LOOP
3601
3602 l_quantifier_index := l_quantifier_index + 1;
3603
3604 END LOOP;
3605 END IF;
3606
3607 IF ( l_instances_index > 1 AND l_instances_index >= l_quantifier_index AND
3608 NVL ( p_input_context.context_type, const_context_generic ) <> const_context_aggregatesum ) THEN
3609
3610 --There is a port variable in the path, and it is not the variable itself (l_instances_index > 1),
3611 --so we will have to call instancesOf on IModelDef.
3612
3613 aload_model_def ( p_component_id );
3614
3615 END IF;
3616
3617 push_variable ( p_complete_path ( l_count ), NULL );
3618 l_key := TO_CHAR ( p_complete_path ( l_count ));
3619
3620 l_singleton_count := 0;
3621
3622 FOR i IN REVERSE 1..l_count - 1 LOOP
3623
3624 --(need to include 'bommodel' below to support rare cases of old upgraded models, bug #6613028).
3625
3626 IF ( h_psnid_detailedtype ( p_complete_path ( i + 1 )) IN ( h_psntypes ('singleton'), h_psntypes ('bomoptionclass'), h_psntypes ('bommodel'))) THEN
3627
3628 l_singleton_count := l_singleton_count + 1;
3629
3630 push_variable ( p_complete_path ( i ), 'ISingletonExprDef');
3631 emit_invokevirtual ('ISingletonExprDef.getVarRef(IExprDef)');
3632
3633 ELSIF ( h_psnid_detailedtype ( p_complete_path ( i + 1 )) IN ( h_psntypes ('component'), h_psntypes ('reference'), h_psntypes ('connector'))) THEN
3634
3635 IF ( p_input_context.context_type = const_context_aggregatesum ) THEN
3636
3637 IF ( i + 1 < l_instances_index ) THEN
3638
3639 emit_invokevirtual('IPortExprDef.hierarchicalUnion(IPortExprDef)');
3640
3641 END IF;
3642
3643 push_variable ( p_complete_path ( i ), 'IPortExprDef');
3644 l_return := const_resourcesum_required;
3645
3646 ELSE
3647
3648 IF ( i + 1 = l_instances_index ) THEN
3649
3650 --For the most shallow port down the path need to use this signature.
3651
3652 IF ( l_instances_index >= l_quantifier_index ) THEN
3653
3654 --This condition is required for contributors, because in this case first component
3655 --does not necessarily need instancesOf.
3656
3657 emit_invokevirtual('IModelDef.instancesOf(IPortExprDef)');
3658
3659 END IF;
3660
3661 ELSIF ( i + 1 >= l_quantifier_index ) THEN
3662
3663 --We are still above the deepest port.
3664
3665 emit_invokevirtual('IInstanceQuantifier.instancesOf(IPortExprDef)');
3666
3667 END IF;
3668
3669 IF ( i + 1 = l_quantifier_index ) THEN
3670
3671 --We need to collect only distinct instance quantifiers.
3672
3673 IF ( p_input_context.context_type IN ( const_context_contributor, const_context_target)) THEN
3674
3675 t_acc_local_quantifiers ( t_acc_local_quantifiers.COUNT + 1 ) := l_key;
3676
3677 IF ( NOT h_acc_quantifiers ( l_target_count ).EXISTS ( l_key )) THEN
3678
3679 l_acc_count := t_acc_quantifiers ( l_target_count ).COUNT + 1;
3680
3681 t_acc_quantifiers ( l_target_count )( l_acc_count ) := l_key;
3682 h_acc_quantifiers ( l_target_count )( l_key ) := 1;
3683
3684 copyto_register ( l_key );
3685
3686 END IF;
3687
3688 ELSE
3689
3690 IF ( NOT h_instancequantifiers.EXISTS ( l_key )) THEN
3691
3692 t_instancequantifiers ( t_instancequantifiers.COUNT + 1 ) := l_key;
3693 h_instancequantifiers ( l_key ) := 1;
3694
3695 copyto_local_variable ( l_key );
3696
3697 END IF;
3698 END IF;
3699
3700 l_return := const_quantifier_created;
3701
3702 END IF;
3703
3704 --Note that if we are below the path's instance quantifier (i + 1 < l_quantifier_index)
3705 --and still are on a port, we are generating a contributor, because for a regular node
3706 --path's instance quantifier will be on the deepest port.
3707
3708 l_contrib_index := i + 2 + l_singleton_count;
3709
3710 IF ( l_return = const_quantifier_created AND l_contrib_index = l_quantifier_index ) THEN
3711
3712 emit_invokevirtual('IInstanceQuantifier.getExprFromInstance(IExprDef)');
3713
3714 END IF;
3715
3716 IF ( l_contrib_index < l_quantifier_index ) THEN
3717
3718 emit_invokevirtual('IPortExprDef.hierarchicalUnion(IPortExprDef)');
3719 push_variable ( p_complete_path ( i ), 'IPortExprDef');
3720
3721 l_return := const_resourcesum_required;
3722
3723 ELSIF ( l_contrib_index = l_quantifier_index ) THEN
3724
3725 push_variable ( p_complete_path ( i ), 'IPortExprDef');
3726 l_return := const_resourcesum_required;
3727
3728 ELSE
3729
3730 push_variable ( p_complete_path ( i ), 'IInstanceQuantifier');
3731
3732 END IF;
3733 END IF;
3734
3735 l_singleton_count := 0;
3736
3737 END IF;
3738
3739 l_key := l_key || '_' || TO_CHAR ( p_complete_path ( i ));
3740
3741 END LOOP;
3742
3743 IF ( p_input_context.context_type = const_context_aggregatesum ) THEN
3744 IF ( h_psnid_detailedtype ( p_complete_path ( 1 )) IN ( h_psntypes ('component'), h_psntypes ('reference'), h_psntypes ('connector'))) THEN
3745
3746 IF ( l_instances_index > 1 ) THEN
3747
3748 emit_invokevirtual('IPortExprDef.hierarchicalUnion(IPortExprDef)');
3749
3750 END IF;
3751
3752 l_return := const_resourcesum_required;
3753
3754 END IF;
3755 END IF;
3756
3757 RETURN l_return;
3758 END generate_path;
3759 ----------------------------------------------------------------------------------
3760 -- Scope: compile_constraints
3761 FUNCTION generate_path ( p_node_id IN NUMBER
3762 , p_expl_id IN NUMBER
3763 , p_input_context IN expression_context
3764 , x_output_context IN OUT NOCOPY expression_context
3765 ) RETURN PLS_INTEGER IS
3766
3767 l_target_key VARCHAR2(4000);
3768 l_target_count PLS_INTEGER;
3769
3770 l_acc_init type_varchar4000_table;
3771 h_acc_init type_data_hashtable;
3772 tl_complete_path type_number_table;
3773
3774 BEGIN
3775
3776 IF ( p_input_context.context_type = const_context_target ) THEN
3777
3778 --In general, this key should contain more information about the target,
3779 --such as properties, applied to the target.
3780
3781 l_target_key := TO_CHAR ( p_node_id ) || ':' || TO_CHAR ( p_expl_id );
3782
3783 x_output_context.context_type := const_context_target;
3784 x_output_context.context_data := l_target_key;
3785
3786 t_acc_target_sequence ( t_acc_targets.COUNT + 1 ) := 0;
3787 t_acc_targets ( t_acc_targets.COUNT + 1 ) := l_target_key;
3788
3789 l_target_count := t_acc_targets.COUNT;
3790
3791 h_acc_targets ( l_target_key ) := l_target_count;
3792 t_acc_quantifiers ( l_target_count ) := l_acc_init;
3793 h_acc_quantifiers ( l_target_count ) := h_acc_init;
3794
3795 x_output_context.context_num_data := l_target_count;
3796
3797 END IF;
3798
3799 tl_complete_path := build_complete_path ( p_node_id, p_expl_id );
3800
3801 IF ( p_input_context.context_type = const_context_target ) THEN
3802
3803 t_acc_complete_path ( l_target_count ) := tl_complete_path;
3804
3805 END IF;
3806
3807 IF ( tl_complete_path.COUNT = 0 ) THEN RETURN const_no_instances; END IF;
3808
3809 RETURN generate_path ( tl_complete_path, p_input_context, x_output_context );
3810
3811 END generate_path;
3812 ----------------------------------------------------------------------------------
3813 -- Scope: compile_constraints
3814 PROCEDURE generate_quantifier ( p_key IN VARCHAR2 ) IS
3815
3816 tl_complete_path type_number_table;
3817 l_count PLS_INTEGER;
3818
3819 l_instancesOf VARCHAR2(4000);
3820
3821 BEGIN
3822
3823 tl_complete_path := split_path ( p_key );
3824 l_count := tl_complete_path.COUNT;
3825
3826 IF ( l_count = 0 ) THEN RETURN; END IF;
3827
3828 l_instancesOf := 'IModelDef.instancesOf(IPortExprDef)';
3829
3830 aload_model_def ( p_component_id );
3831 push_variable ( tl_complete_path ( l_count ), NULL );
3832
3833 FOR i IN REVERSE 1..l_count - 1 LOOP
3834
3835 IF ( h_psnid_detailedtype ( tl_complete_path ( i + 1 )) IN ( h_psntypes ('singleton'), h_psntypes ('bomoptionclass'))) THEN
3836
3837 push_variable ( tl_complete_path ( i ), 'ISingletonExprDef');
3838 emit_invokevirtual ('ISingletonExprDef.getVarRef(IExprDef)');
3839
3840 ELSE --(h_psntypes ('component'), h_psntypes ('reference'), h_psntypes ('connector'))
3841
3842 emit_invokevirtual( l_instancesOf );
3843 l_instancesOf := 'IInstanceQuantifier.instancesOf(IPortExprDef)';
3844
3845 push_variable ( tl_complete_path ( i ), 'IInstanceQuantifier');
3846
3847 END IF;
3848 END LOOP;
3849
3850 emit_invokevirtual( l_instancesOf );
3851 copyto_local_variable ( p_key );
3852
3853 END generate_quantifier;
3854 ----------------------------------------------------------------------------------
3855 -- Scope: compile_constraints
3856 PROCEDURE aload_quantifier ( p_key IN VARCHAR2 ) IS
3857 BEGIN
3858
3859 IF ( NOT local_variable_defined ( p_key )) THEN
3860
3861 generate_quantifier ( p_key );
3862
3863 ELSE
3864
3865 aload_local_variable ( p_key );
3866
3867 END IF;
3868 END aload_quantifier;
3869 ----------------------------------------------------------------------------------
3870 -- Scope: compile_constraints
3871 PROCEDURE apply_bom_property ( p_property IN VARCHAR2 ) IS
3872 BEGIN
3873
3874 emit_dup ();
3875 emit_invokevirtual ('ISingletonExprDef.getType()');
3876 emit_invokevirtual ( p_property );
3877 emit_invokevirtual ('ISingletonExprDef.getVarRef(IExprDef)');
3878
3879 END apply_bom_property;
3880 ----------------------------------------------------------------------------------
3881 PROCEDURE any_option_selected IS
3882 BEGIN
3883
3884 emit_invokevirtual ('ISetExprDef.card()');
3885 push_integer_constant ( 0 );
3886 emit_invokevirtual('INumExprDef.gt(int)');
3887
3888 END any_option_selected;
3889 ----------------------------------------------------------------------------------
3890 -- Scope: compile_constraints
3891 PROCEDURE all_options_selected ( p_card IN PLS_INTEGER ) IS
3892 BEGIN
3893
3894 emit_invokevirtual ('ISetExprDef.card()');
3895 push_integer_constant ( p_card );
3896 emit_invokevirtual('INumExprDef.eq(int)');
3897
3898 END all_options_selected;
3899 ----------------------------------------------------------------------------------
3900 -- Scope: compile_constraints
3901 FUNCTION get_context_type ( j IN PLS_INTEGER ) RETURN PLS_INTEGER IS
3902
3903 l_index PLS_INTEGER;
3904
3905 BEGIN
3906
3907 l_index := h_exprid_backindex ( TO_CHAR ( t_exp_exprparentid ( j )));
3908
3909 CASE t_exp_exprtype ( l_index ) WHEN h_exprtypes ('operator') THEN
3910
3911 IF ( t_exp_templateid ( l_index ) IN (
3912 h_templates ('and')
3913 , h_templates ('or')
3914 , h_templates ('not')
3915 )) THEN
3916
3917 RETURN h_datatypes ('boolean');
3918
3919 ELSIF ( t_exp_templateid ( l_index ) IN (
3920 h_templates ('equals')
3921 , h_templates ('notequals')
3922 , h_templates ('gt')
3923 , h_templates ('lt')
3924 , h_templates ('ge')
3925 , h_templates ('le')
3926 , h_templates ('add')
3927 , h_templates ('subtract')
3928 , h_templates ('multiply')
3929 , h_templates ('div')
3930 , h_templates ('neg')
3931 , h_templates ('totext')
3932 )) THEN
3933
3934 --Note, that ToText operator means numeric context for its argument. That means that ToText
3935 --cannot be applied to a text argument. May need to change if this is a problem.
3936
3937 RETURN h_datatypes ('decimal');
3938
3939 ELSIF ( t_exp_templateid ( l_index ) IN (
3940 h_templates ('doesnotbeginwith')
3941 , h_templates ('doesnotendwith')
3942 , h_templates ('doesnotcontain')
3943 , h_templates ('notlike')
3944 , h_templates ('concatenate')
3945 , h_templates ('beginswith')
3946 , h_templates ('endswith')
3947 , h_templates ('contains')
3948 , h_templates ('like')
3949 , h_templates ('matches')
3950 , h_templates('textequals')
3951 , h_templates('textnotequals')
3952 )) THEN
3953
3954 RETURN h_datatypes ('text');
3955
3956 ELSE
3957 -- 'Unknown operator type "^OPERTYPE" in the rule. Rule "^RULE_NAME" in the Model ^MODEL_NAME" ignored.';
3958 report_and_raise_rule_sys_warn(
3959 GET_NOT_TRANSLATED_TEXT(CZ_FCE_SW_UNKNOWN_OP_TYPE,
3960 'OPERTYPE', TO_CHAR(t_exp_templateid ( j ))),
3961 'get_context_type'
3962 );
3963 RETURN NULL;
3964 END IF;
3965
3966 ELSE
3967 -- 'Unable to get context data type for expression node with the id "^EXPR_ID". Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
3968 report_and_raise_rule_sys_warn(
3969 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_RE_ENODE_NO_DTYPE,
3970 'EXPR_ID', l_index),
3971 p_warning_location => 'get_context_type');
3972 RETURN NULL;
3973
3974 END CASE;
3975 END get_context_type;
3976 ----------------------------------------------------------------------------------
3977 -- Scope: compile_constraints
3978 FUNCTION logical_context ( j IN PLS_INTEGER, p_context_type IN PLS_INTEGER ) RETURN BOOLEAN IS
3979
3980 l_parent_id VARCHAR2(4000);
3981 l_child PLS_INTEGER;
3982 l_index PLS_INTEGER;
3983
3984 BEGIN
3985
3986 IF ( p_context_type = const_context_logical ) THEN RETURN TRUE; END IF;
3987
3988 l_parent_id := TO_CHAR ( t_exp_exprparentid ( j ));
3989 IF ( l_parent_id IS NULL ) THEN RETURN FALSE; END IF;
3990
3991 l_index := h_exprid_backindex ( l_parent_id );
3992
3993 IF ( h_logical_ops.EXISTS ( t_exp_templateid ( l_index ))) THEN RETURN TRUE; END IF;
3994
3995 --Bug #7026587. Check the special case when the other operand of equality operator is a boolean literal.
3996
3997 IF ( t_exp_templateid ( l_index ) IN ( h_templates ('equals'), h_templates ('notequals'))) THEN
3998
3999 l_child := h_exprid_childrenindex ( l_parent_id );
4000 IF ( l_child = j ) THEN l_child := l_child + 1; END IF;
4001
4002 IF ( t_exp_exprtype ( l_child ) = h_exprtypes ('literal') AND t_exp_datatype ( l_child ) = h_datatypes ('boolean')) THEN
4003
4004 RETURN TRUE;
4005
4006 END IF;
4007 END IF;
4008
4009 RETURN FALSE;
4010 END logical_context;
4011 ----------------------------------------------------------------------------------
4012 -- Scope: compile_constraints
4013 FUNCTION numeric_context ( j IN PLS_INTEGER, p_context_type IN PLS_INTEGER ) RETURN BOOLEAN IS
4014
4015 l_parent_id VARCHAR2(4000);
4016 l_child PLS_INTEGER;
4017 l_index PLS_INTEGER;
4018
4019 BEGIN
4020
4021 IF ( p_context_type IN ( const_context_numeric, const_context_contributor, const_context_target, const_context_aggregatesum )) THEN
4022
4023 RETURN TRUE;
4024
4025 END IF;
4026
4027 l_parent_id := TO_CHAR ( t_exp_exprparentid ( j ));
4028 IF ( l_parent_id IS NULL ) THEN RETURN FALSE; END IF;
4029
4030 l_index := h_exprid_backindex ( l_parent_id );
4031
4032 IF (NOT h_numeric_ops.EXISTS ( t_exp_templateid ( l_index ))) THEN RETURN FALSE; END IF;
4033
4034 --Bug #7026587. Check the special case when the other operand of equality operator is a boolean literal.
4035
4036 IF ( t_exp_templateid ( l_index ) IN ( h_templates ('equals'), h_templates ('notequals'))) THEN
4037
4038 l_child := h_exprid_childrenindex ( l_parent_id );
4039 IF ( l_child = j ) THEN l_child := l_child + 1; END IF;
4040
4041 IF ( t_exp_exprtype ( l_child ) = h_exprtypes ('literal') AND t_exp_datatype ( l_child ) = h_datatypes ('boolean')) THEN
4042
4043 RETURN FALSE;
4044
4045 END IF;
4046 END IF;
4047
4048 RETURN TRUE;
4049 END numeric_context;
4050 ----------------------------------------------------------------------------------
4051 -- Scope: compile_constraints
4052 PROCEDURE apply_bom_logical_context ( p_node_id IN NUMBER, p_instances IN PLS_INTEGER ) IS
4053
4054 l_type NUMBER;
4055
4056 BEGIN
4057
4058 l_type := h_psnid_detailedtype ( TO_CHAR ( p_node_id ));
4059
4060 IF ( l_type IN ( h_psntypes ('bomoptionclass'), h_psntypes ('bomstandard'))) THEN
4061
4062 apply_bom_property ('IBomDef.selected()');
4063 IF ( p_instances = const_quantifier_created ) THEN emit_invokevirtual('IInstanceQuantifier.getExprFromInstance(IExprDef)'); END IF;
4064
4065 ELSIF ( l_type IN ( h_psntypes ('reference'), h_psntypes ('connector'))) THEN
4066
4067 IF ( p_instances = const_quantifier_created ) THEN emit_invokevirtual('IInstanceQuantifier.getExprFromInstance(IExprDef)'); END IF;
4068
4069 emit_invokevirtual ('IPortExprDef.card()');
4070 push_integer_constant ( 0 );
4071 emit_invokevirtual('INumExprDef.gt(int)');
4072
4073 ELSE
4074
4075 --#<should never happen>
4076 -- 'Type ^TYPE is not a known BOM child node type. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
4077 report_and_raise_rule_sys_warn(
4078 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_BOM_INVAL_CHILD_TYP,
4079 'TYPE', l_type ),
4080 p_warning_location => 'apply_bom_logical_context');
4081
4082 END IF;
4083 END apply_bom_logical_context;
4084 ----------------------------------------------------------------------------------
4085 -- Scope: compile_constraints
4086 PROCEDURE apply_logical_context ( p_node_id IN NUMBER, p_context_type IN PLS_INTEGER ) IS
4087
4088 l_type NUMBER;
4089
4090 BEGIN
4091
4092 l_type := h_psnid_detailedtype ( TO_CHAR ( p_node_id ));
4093
4094 IF ( l_type IN ( h_psntypes ('bomoptionclass'), h_psntypes ('bomstandard'))) THEN
4095
4096 apply_bom_property ('IBomDef.selected()');
4097
4098 ELSIF ( l_type = h_psntypes ('bommodel')) THEN
4099
4100 IF ( p_node_id <> p_component_id ) THEN
4101
4102 --Bug #6779671. This call is required only if the property is not applied to the root bom model itself.
4103
4104 emit_dup ();
4105 emit_invokevirtual ('IInstanceQuantifier.getType()');
4106
4107 ELSE
4108
4109 aload_model_def ( p_node_id );
4110
4111 END IF;
4112
4113 emit_invokevirtual ('IBomDef.selected()');
4114
4115 ELSIF ( l_type = h_psntypes ('optionfeature')) THEN
4116
4117 any_option_selected ();
4118
4119 ELSIF ( l_type IN ( h_psntypes ('reference'), h_psntypes ('connector'))) THEN
4120
4121 emit_invokevirtual ('IPortExprDef.card()');
4122 push_integer_constant ( 0 );
4123 emit_invokevirtual('INumExprDef.gt(int)');
4124
4125 ELSIF ( l_type = h_psntypes ('integerfeature')) THEN
4126
4127 push_integer_constant ( 0 );
4128 emit_invokevirtual('INumExprDef.gt(int)');
4129
4130 ELSIF ( l_type = h_psntypes ('option')) THEN
4131
4132 push_variable_name ( p_node_id );
4133
4134 IF ( p_context_type = const_context_contributor ) THEN
4135
4136 emit_invokevirtual ('ISetExprDef.elementCount(Object)');
4137
4138 ELSE
4139
4140 emit_invokevirtual ('ISetExprDef.contains(Object)');
4141
4142 END IF;
4143 END IF;
4144 END apply_logical_context;
4145 ----------------------------------------------------------------------------------
4146 -- Scope: compile_constraints
4147 PROCEDURE apply_numeric_context ( p_node_id IN NUMBER, p_context_type IN PLS_INTEGER ) IS
4148
4149 l_node_id VARCHAR2(4000);
4150 l_index PLS_INTEGER;
4151 l_type NUMBER;
4152
4153 BEGIN
4154
4155 l_node_id := TO_CHAR ( p_node_id );
4156
4157 l_type := h_psnid_detailedtype ( l_node_id );
4158 l_index := h_psnid_backindex ( l_node_id );
4159
4160 IF ( l_type IN ( h_psntypes ('bomoptionclass'), h_psntypes ('bomstandard'))) THEN
4161
4162 apply_bom_property ('IBomDef.absQty()');
4163
4164 ELSIF ( l_type = h_psntypes ('bommodel')) THEN
4165
4166 IF ( p_node_id <> p_component_id ) THEN
4167
4168 --Bug #6779671. This call is required only if the property is not applied to the root bom model itself.
4169
4170 emit_dup ();
4171 emit_invokevirtual ('IInstanceQuantifier.getType()');
4172
4173 ELSE
4174
4175 aload_model_def ( p_node_id );
4176
4177 END IF;
4178
4179 emit_invokevirtual ('IBomDef.absQty()');
4180
4181 ELSIF ( l_type IN ( h_psntypes ('reference'), h_psntypes ('connector'))) THEN
4182
4183 emit_invokevirtual ('IPortExprDef.card()');
4184
4185 ELSIF ( l_type = h_psntypes ('optionfeature')) THEN
4186
4187 emit_invokevirtual ('ISetExprDef.card()');
4188
4189 ELSIF ( l_type = h_psntypes ('option')) THEN
4190
4191 --Solver has introduced a new method that can be used in numeric context
4192 --for options universally (Re: bug #6733300).
4193
4194 push_variable_name ( l_node_id );
4195 emit_invokevirtual ('ISetExprDef.elementCount(Object)');
4196
4197 END IF;
4198 END apply_numeric_context;
4199 ----------------------------------------------------------------------------------
4200 -- Scope: compile_constraints
4201 PROCEDURE apply_system_property ( p_template_id IN NUMBER
4202 , p_index IN NUMBER
4203 , p_input_context IN expression_context
4204 ) IS
4205
4206 l_is_bom BOOLEAN;
4207 l_is_bomreference BOOLEAN;
4208
4209 l_return NUMBER;
4210
4211 BEGIN
4212
4213 l_is_bom := is_bom_node ( p_index );
4214 l_is_bomreference := is_bom_port ( p_index );
4215
4216 IF ( p_template_id = h_templates ('state')) THEN
4217
4218 apply_logical_context ( t_psn_psnodeid ( p_index ), p_input_context.context_type);
4219
4220 ELSIF ( h_quantities.EXISTS ( p_template_id ) OR p_template_id = h_templates ('selectioncount')) THEN
4221
4222 IF ( l_is_bom or l_is_bomreference ) THEN
4223
4224 IF ( t_psn_psnodetype ( p_index ) <> h_psntypes ('bommodel')) THEN
4225
4226 --This call is required only if the property is not applied to the root bom model itself.
4227 --If the property cannot be applied to the root model, this condition can be removed.
4228
4229 emit_dup ();
4230
4231 IF ( l_is_bom ) THEN
4232
4233 emit_invokevirtual ('ISingletonExprDef.getType()');
4234
4235 ELSE
4236
4237 IF ( p_input_context.context_type = const_context_contributor ) THEN
4238
4239 emit_invokevirtual ( 'IPortExprDef.getType()');
4240
4241 ELSE
4242
4243 emit_invokevirtual ( 'IInstanceQuantifier.getType()');
4244
4245 END IF;
4246 END IF;
4247
4248 ELSE
4249
4250 aload_model_def ( t_psn_psnodeid ( p_index ));
4251
4252 END IF;
4253
4254 IF ( h_quantities.EXISTS ( p_template_id )) THEN
4255
4256 emit_invokevirtual ( h_quantities ( p_template_id ));
4257
4258 ELSE
4259
4260 --This is selectionCount property.
4261
4262 emit_invokevirtual ('IBomDef.getOCCardSet()');
4263 emit_invokevirtual ('ISetExprDef.card()');
4264
4265 END IF;
4266
4267 ELSE
4268
4269 IF ( t_psn_detailedtype ( p_index ) = h_psntypes ('optionfeature')) THEN
4270
4271 IF ( p_template_id = h_templates ('selectioncount') AND t_psn_countedoptionsflag ( p_index ) = '1' ) THEN
4272
4273 --Property is applied to a Counted Option Feature.
4274
4275 emit_invokevirtual ('IBagExprDef.count()');
4276
4277 ELSE
4278
4279 emit_invokevirtual ('ISetExprDef.card()');
4280
4281 END IF;
4282
4283 ELSIF ( t_psn_detailedtype ( p_index ) = h_psntypes ('option')) THEN
4284
4285 --This is the same code as in apply_numeric_context to an option. The procedure
4286 --is not used here because it checks whether the node is bom, and this has been
4287 --done already at this point.
4288
4289 push_variable_name ( TO_CHAR ( t_psn_psnodeid ( p_index )));
4290 emit_invokevirtual ('ISetExprDef.elementCount(Object)');
4291
4292 END IF;
4293 END IF;
4294
4295 ELSIF ( p_template_id = h_templates ('instancecount')) THEN
4296
4297 -- Property ^PROP_NAME is only applicable to nodes that can contain instances. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
4298
4299 l_return := get_port_id ( TO_CHAR ( t_psn_psnodeid ( p_index )));
4300
4301 IF ( l_return IS NULL ) THEN
4302
4303 report_and_raise_rule_warning (
4304 p_text => CZ_UTILS.GET_TEXT(
4305 CZ_FCE_W_PROP_ONLY_ICOMP_REF,
4306 'PROP_NAME', 'InstanceCount()',
4307 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
4308 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path)),
4309 p_warning_location => 'apply_system_property');
4310
4311 END IF;
4312
4313 emit_invokevirtual ('IPortExprDef.card()');
4314
4315 ELSIF ( p_template_id NOT IN ( h_templates ('value')
4316 , h_templates ('integervalue')
4317 , h_templates ('decimalvalue')
4318 )) THEN
4319
4320 --#<should never happen>
4321 -- 'Unknown property template "^TEMPLATE" found. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
4322 report_and_raise_rule_sys_warn(
4323 p_text => GET_NOT_TRANSLATED_TEXT(
4324 CZ_FCE_SW_UNKNOWN_TEMPLATE,
4325 'TEMPLATE', p_template_id ),
4326 p_warning_location => 'apply_system_property' );
4327
4328 END IF;
4329
4330 IF ( l_is_bom AND t_psn_psnodetype ( p_index ) <> h_psntypes ('bommodel') AND p_template_id <> h_templates ('state')) THEN
4331
4332 --For 'state' this call has already been done.
4333
4334 emit_invokevirtual ('ISingletonExprDef.getVarRef(IExprDef)');
4335
4336 END IF;
4337 END apply_system_property;
4338 ----------------------------------------------------------------------------------
4339 -- Scope: compile_constraints
4340 PROCEDURE generate_system_property ( p_template_id IN NUMBER
4341 , p_node_id IN NUMBER
4342 , p_expl_id IN NUMBER
4343 , p_input_context IN expression_context
4344 , x_output_context IN OUT NOCOPY expression_context
4345 ) IS
4346
4347 l_return PLS_INTEGER;
4348 l_index PLS_INTEGER;
4349
4350 l_is_bom BOOLEAN;
4351 l_is_bomreference BOOLEAN;
4352
4353 BEGIN
4354
4355 l_index := h_psnid_backindex ( TO_CHAR ( p_node_id ));
4356 l_is_bom := is_bom_node ( l_index );
4357 l_is_bomreference := is_bom_port ( l_index );
4358
4359 IF ( l_is_bomreference AND ( h_quantities.EXISTS ( TO_CHAR ( p_template_id )) OR p_template_id = h_templates ('selectioncount'))) THEN
4360
4361 l_return := generate_path ( t_psn_referenceid ( l_index ), p_expl_id, p_input_context, x_output_context );
4362
4363 ELSE
4364
4365 l_return := generate_path ( t_psn_psnodeid ( l_index ), p_expl_id, p_input_context, x_output_context );
4366
4367 END IF;
4368
4369 IF ( l_return = const_quantifier_created AND ( NOT ( l_is_bom OR l_is_bomreference ))) THEN
4370
4371 --If this is not a bom node and it is necessary to apply getExprFromInstance, we need to
4372 --do it before applying the property.
4373
4374 emit_invokevirtual('IInstanceQuantifier.getExprFromInstance(IExprDef)');
4375
4376 END IF;
4377
4378 apply_system_property ( p_template_id, l_index, p_input_context );
4379
4380 IF ( p_input_context.context_type = const_context_contributor AND l_is_bomreference AND h_quantities.EXISTS ( TO_CHAR ( p_template_id ))) THEN
4381
4382 l_return := const_resourcesum_required;
4383
4384 END IF;
4385
4386 IF ( l_is_bom OR l_is_bomreference ) THEN
4387
4388 --For bom nodes, the result of applying property is a variable, so, if necessary, we need to call
4389 --getExprFromInstance on this variable.
4390
4391 IF ( l_return = const_quantifier_created ) THEN emit_invokevirtual('IInstanceQuantifier.getExprFromInstance(IExprDef)'); END IF;
4392
4393 END IF;
4394
4395 IF ( l_return = const_resourcesum_required ) THEN
4396
4397 emit_invokevirtual('IPortExprDef.sum(INumExprDef)');
4398
4399 END IF;
4400 END generate_system_property;
4401 ----------------------------------------------------------------------------------
4402 -- Scope: compile_constraints
4403 PROCEDURE apply_context ( p_node_id IN NUMBER, p_instance IN PLS_INTEGER, p_input_context IN PLS_INTEGER ) IS
4404
4405 l_index PLS_INTEGER;
4406 l_is_bom BOOLEAN;
4407
4408 BEGIN
4409
4410 l_index := h_psnid_backindex ( TO_CHAR ( p_node_id));
4411 l_is_bom := is_bom_node ( l_index );
4412
4413 IF ( p_input_context = const_context_logical ) THEN
4414
4415 apply_logical_context ( p_node_id, p_input_context );
4416
4417 END IF;
4418
4419 END apply_context;
4420 ----------------------------------------------------------------------------------
4421 --Nodes other than targets and contributors can be stored in local variables using
4422 --the following key:
4423
4424 --ps_node_id-model_ref_expl_id
4425
4426 --This procedure can be used to restore such nodes from the local variable. The
4427 --path will be regenerated if necessary. Note that if this node has an instance
4428 --quantifier, associated with it, the key for this quanitifer will be added to
4429 --the global quantifier arrays so that if this node participates in constraint,
4430 --correct ForAll will be generated by addConstraint call.
4431
4432 --The input context is not passed to generate_path. It is only used to apply to
4433 --the context after path is generated.
4434 -- Scope: compile_constraints
4435 PROCEDURE aload_context_node ( p_key IN VARCHAR2, p_input_context IN PLS_INTEGER ) IS
4436
4437 l_input_context expression_context;
4438 l_output_context expression_context;
4439
4440 l_return PLS_INTEGER;
4441 l_index PLS_INTEGER;
4442 l_count PLS_INTEGER;
4443 l_node_id NUMBER;
4444 l_expl_id NUMBER;
4445
4446 tl_complete_path type_number_table;
4447 l_key VARCHAR2(4000);
4448
4449 BEGIN
4450
4451 l_node_id := TO_NUMBER ( SUBSTR ( p_key, 1, INSTR ( p_key, '-' ) - 1));
4452 l_expl_id := TO_NUMBER ( SUBSTR ( p_key, INSTR ( p_key, '-' ) + 1));
4453
4454 IF ( NOT local_variable_defined ( p_key )) THEN
4455
4456 l_return := generate_path ( l_node_id, l_expl_id, l_input_context, l_output_context );
4457
4458 ELSE
4459
4460 --If the variable is defined, we need to also take care of related quantifiers if any.
4461 --We just add them to the global quantifier arrays, the rest will be done by
4462 --aload_quantifier when necessary.
4463
4464 aload_local_variable ( p_key );
4465
4466 tl_complete_path := build_complete_path ( l_node_id, l_expl_id );
4467 l_count := tl_complete_path.COUNT;
4468
4469 IF ( l_count > 0 ) THEN
4470
4471 --Find the deepest port, this will be the instance quantifier to use in forAll.
4472
4473 l_index := 2;
4474
4475 --#<important>
4476 --Using h_psnid_detailedtype is very essential here and in the next block. If any changes are made
4477 --to the definition of h_psnid_detailedtype array, this code may need to change.
4478
4479 WHILE ( l_index <= l_count AND h_psnid_detailedtype ( tl_complete_path ( l_index )) NOT IN
4480 (h_psntypes ('component'), h_psntypes ('reference'), h_psntypes ('connector'))) LOOP
4481
4482 l_index := l_index + 1;
4483
4484 END LOOP;
4485
4486 l_key := TO_CHAR ( tl_complete_path ( l_count ));
4487
4488 FOR i IN REVERSE l_index..l_count - 1 LOOP
4489
4490 l_key := l_key || '_' || TO_CHAR ( tl_complete_path ( i ));
4491
4492 END LOOP;
4493
4494 IF ( l_index <= l_count ) THEN
4495
4496 IF ( NOT h_instancequantifiers.EXISTS ( l_key )) THEN
4497
4498 t_instancequantifiers ( t_instancequantifiers.COUNT + 1 ) := l_key;
4499 h_instancequantifiers ( l_key ) := 1;
4500
4501 END IF;
4502 END IF;
4503 END IF;
4504 END IF;
4505
4506 apply_context ( l_node_id, l_return, p_input_context );
4507
4508 END aload_context_node;
4509 ----------------------------------------------------------------------------------
4510 -- Scope: compile_constraints
4511 PROCEDURE generate_node ( j IN PLS_INTEGER
4512 , p_input_context IN expression_context
4513 , x_output_context IN OUT NOCOPY expression_context
4514 ) IS
4515
4516 l_return PLS_INTEGER;
4517 l_node_id NUMBER;
4518 l_is_bom BOOLEAN;
4519 l_index PLS_INTEGER;
4520
4521 BEGIN
4522
4523 l_node_id := t_exp_psnodeid ( j );
4524 l_index := h_psnid_backindex ( TO_CHAR ( l_node_id ));
4525
4526 l_is_bom := is_bom_node ( l_index );
4527
4528 l_return := generate_path ( t_exp_psnodeid ( j ), t_exp_modelrefexplid ( j ), p_input_context, x_output_context );
4529
4530 IF ( l_return = const_quantifier_created AND ( NOT l_is_bom )) THEN
4531
4532 emit_invokevirtual('IInstanceQuantifier.getExprFromInstance(IExprDef)');
4533
4534 END IF;
4535
4536 IF ( logical_context ( j, p_input_context.context_type )) THEN
4537
4538 apply_logical_context ( l_node_id, p_input_context.context_type );
4539
4540 ELSIF ( numeric_context ( j, p_input_context.context_type )) THEN
4541
4542 apply_numeric_context ( l_node_id, p_input_context.context_type );
4543
4544 END IF;
4545
4546 IF ( l_return = const_quantifier_created AND l_is_bom ) THEN
4547
4548 emit_invokevirtual('IInstanceQuantifier.getExprFromInstance(IExprDef)');
4549
4550 END IF;
4551
4552 IF ( l_return = const_resourcesum_required ) THEN
4553
4554 emit_invokevirtual('IPortExprDef.sum(INumExprDef)');
4555
4556 END IF;
4557 END generate_node;
4558 ----------------------------------------------------------------------------------
4559 -- Scope: compile_constraints
4560 PROCEDURE generate_logical_options ( j IN PLS_INTEGER
4561 , p_input_context IN expression_context
4562 , x_output_context IN OUT NOCOPY expression_context
4563 ) IS
4564
4565 l_parent_id VARCHAR2(4000);
4566 l_node_id VARCHAR2(4000);
4567 l_expl_id NUMBER;
4568
4569 l_logic_operator NUMBER;
4570
4571 l_last_index PLS_INTEGER;
4572 l_index PLS_INTEGER;
4573 l_return PLS_INTEGER;
4574
4575 t_children type_iteratornode_table;
4576
4577 BEGIN
4578
4579 l_parent_id := TO_CHAR ( t_exp_exprparentid ( j ));
4580
4581 IF ( l_parent_id IS NULL ) THEN
4582
4583 --#<should never happen>
4584 report_and_raise_rule_sys_warn(
4585 p_text => GET_NOT_TRANSLATED_TEXT(
4586 CZ_FCE_SW_OPTIONS_PARENT_NULL),
4587 p_warning_location => 'generate_logical_options' );
4588
4589 END IF;
4590
4591 l_node_id := TO_CHAR ( t_exp_psnodeid ( j ));
4592 l_expl_id := t_exp_modelrefexplid ( j );
4593 l_index := h_psnid_backindex ( l_node_id );
4594
4595 --If this is a BOM Reference, switch to the referenced BOM Model.
4596
4597 IF ( is_bom_port ( l_index )) THEN
4598
4599 l_node_id := TO_CHAR ( t_psn_referenceid ( l_index ));
4600 l_index := h_psnid_backindex ( l_node_id );
4601
4602 END IF;
4603
4604 --<#temporary>
4605 --Options() cannot be called on a node that has no children.
4606
4607 IF ( node_has_children ( l_node_id )) THEN
4608
4609 l_last_index := h_psnid_lastchildindex ( l_node_id );
4610
4611 ELSE
4612
4613 -- Node ^NODE_NAME has no children. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
4614
4615 report_and_raise_rule_warning (
4616 p_text => CZ_UTILS.GET_TEXT( CZ_FCE_W_NODE_MUST_HAVE_CHILD,
4617 'NODE_NAME', CZ_FCE_COMPILE_UTILS.GET_NODE_PATH( l_node_id,
4618 ps_node_id_table_to_string(
4619 build_complete_path(l_node_id, l_expl_id))),
4620 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name ),
4621 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH ( p_component_id, p_model_path)
4622 ),
4623 p_warning_location => 'generate_logical_options');
4624
4625 END IF;
4626
4627 l_return := generate_path ( l_node_id, t_exp_modelrefexplid ( j ), p_input_context, x_output_context );
4628
4629 IF ( t_psn_detailedtype ( l_index ) = h_psntypes ('optionfeature')) THEN
4630
4631 l_logic_operator := t_exp_templateid ( h_exprid_backindex ( l_parent_id ));
4632
4633 IF ( l_return = const_quantifier_created ) THEN emit_invokevirtual('IInstanceQuantifier.getExprFromInstance(IExprDef)'); END IF;
4634
4635 CASE l_logic_operator
4636
4637 WHEN h_templates ('anytrue') THEN
4638
4639 any_option_selected ();
4640
4641 WHEN h_templates ('alltrue') THEN
4642
4643 all_options_selected ( h_psnid_numberofchildren ( l_node_id ));
4644
4645 ELSE
4646
4647 -- 'Invalid parent operator "^OPERATOR" for property options(). Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
4648 report_and_raise_rule_sys_warn(
4649 p_text => GET_NOT_TRANSLATED_TEXT(
4650 CZ_FCE_SW_OPTIONS_PARENT_INVA,
4651 'OPERATOR', l_logic_operator),
4652 p_warning_location => 'generate_logical_options' );
4653
4654 END CASE;
4655
4656 ELSE
4657
4658 --We are generating Options() on a bom node, explode its children.
4659
4660 t_children := explode_bom_children ( l_node_id, t_exp_modelrefexplid ( j ), l_index + 1, l_last_index, FALSE );
4661
4662 --Adjust the actual number of children of the parent operator as it may be used for generation.
4663 --We replace the one child with Options() applied by the number of its children.
4664
4665 h_exprid_numberofchildren ( l_parent_id ) := h_exprid_numberofchildren ( l_parent_id ) + t_children.COUNT - 1;
4666
4667 --Store the generated parent in a local variable. This object will be used for each child.
4668
4669 IF ( h_psnid_psnodetype ( l_node_id ) <> h_psntypes ('bommodel')) THEN astore_local_variable ( 'var' ); END IF;
4670
4671 --If there is an instance quantifier, it is now on top of stack. Also need to store.
4672
4673 IF ( l_return = const_quantifier_created ) THEN astore_local_variable ( 'iq' ); END IF;
4674
4675 FOR i IN 1..t_children.COUNT LOOP
4676
4677 IF ( l_return = const_quantifier_created ) THEN aload_local_variable ( 'iq' ); END IF;
4678
4679 IF ( h_psnid_psnodetype ( l_node_id ) = h_psntypes ('bommodel')) THEN
4680
4681 push_variable ( t_children ( i ).ps_node_id, 'IInstanceQuantifier');
4682
4683 ELSE
4684
4685 aload_local_variable ( 'var' );
4686 push_variable ( t_children ( i ).ps_node_id, 'ISingletonExprDef');
4687 emit_invokevirtual ('ISingletonExprDef.getVarRef(IExprDef)');
4688
4689 END IF;
4690
4691 apply_bom_logical_context ( t_children ( i ).ps_node_id, l_return );
4692
4693 END LOOP;
4694 END IF;
4695 END generate_logical_options;
4696 ----------------------------------------------------------------------------------
4697 -- Scope: compile_constraints
4698 PROCEDURE generate_numeric_options ( j IN PLS_INTEGER
4699 , p_template_id IN NUMBER
4700 , p_optional_only IN BOOLEAN
4701 , p_input_context IN expression_context
4702 , x_output_context IN OUT NOCOPY expression_context
4703 ) IS
4704
4705 l_template_id NUMBER := p_template_id;
4706
4707 l_parent_id VARCHAR2(4000);
4708 l_node_id VARCHAR2(4000);
4709 l_expl_id NUMBER;
4710
4711 l_last_index PLS_INTEGER;
4712 l_index PLS_INTEGER;
4713 l_return PLS_INTEGER;
4714
4715 t_children type_iteratornode_table;
4716
4717 BEGIN
4718
4719 l_node_id := TO_CHAR ( t_exp_psnodeid ( j ));
4720 l_expl_id := t_exp_modelrefexplid ( j );
4721 l_index := h_psnid_backindex ( l_node_id );
4722
4723 --If this is a BOM Reference, switch to the referenced BOM Model.
4724
4725 IF ( is_bom_port ( l_index )) THEN
4726
4727 l_node_id := TO_CHAR ( t_psn_referenceid ( l_index ));
4728 l_index := h_psnid_backindex ( l_node_id );
4729
4730 END IF;
4731
4732 --<#temporary>
4733 --Options() cannot be called on a node that has no children.
4734
4735 IF ( node_has_children ( l_node_id )) THEN
4736
4737 l_last_index := h_psnid_lastchildindex ( l_node_id );
4738
4739 ELSE
4740
4741 report_and_raise_rule_warning (
4742 p_text => CZ_UTILS.GET_TEXT( CZ_FCE_W_NODE_MUST_HAVE_CHILD,
4743 'NODE_NAME', CZ_FCE_COMPILE_UTILS.GET_NODE_PATH( l_node_id,
4744 ps_node_id_table_to_string(
4745 build_complete_path(l_node_id, l_expl_id) ) ),
4746 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name ),
4747 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH ( p_component_id, p_model_path)
4748 ),
4749 p_warning_location => 'generate_numeric_options');
4750
4751 END IF;
4752
4753 IF ( t_psn_detailedtype ( l_index ) = h_psntypes ('optionfeature')) THEN
4754
4755 l_return := generate_path ( l_node_id, t_exp_modelrefexplid ( j ), p_input_context, x_output_context );
4756
4757 IF ( l_return = const_quantifier_created ) THEN emit_invokevirtual('IInstanceQuantifier.getExprFromInstance(IExprDef)'); END IF;
4758
4759 --Options() is applied to an option feature. Need to generate card() for both counted or
4760 --non-counted option feature.
4761
4762 emit_invokevirtual ('ISetExprDef.card()');
4763 IF ( l_return = const_resourcesum_required ) THEN emit_invokevirtual('IPortExprDef.sum(INumExprDef)'); END IF;
4764
4765 ELSE
4766
4767 --We are generating Options() on a bom node in numeric context, default the bom property.
4768
4769 IF ( l_template_id IS NULL ) THEN l_template_id := h_templates ('quantity'); END IF;
4770 IF ( NOT h_quantities.EXISTS ( l_template_id )) THEN
4771 -- 'In the numeric context invalid property applied to a BOM node. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
4772 report_and_raise_rule_sys_warn(
4773 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_BOM_NUM_INVALPROP ),
4774 p_warning_location => 'generate_numeric_options' );
4775 END IF;
4776
4777 t_children := explode_bom_children ( l_node_id, t_exp_modelrefexplid ( j ), l_index + 1, l_last_index, p_optional_only );
4778 l_parent_id := TO_CHAR ( t_exp_exprparentid ( j ));
4779
4780 --Adjust the actual number of children of the parent operator as it may be used for generation.
4781 --We replace the one child with Options() applied by the number of its children.
4782
4783 h_exprid_numberofchildren ( l_parent_id ) := h_exprid_numberofchildren ( l_parent_id ) + t_children.COUNT - 1;
4784
4785 IF ( t_children.COUNT > 2 ) THEN
4786
4787 --If there are more than two chilren, we will be summing them up later, so we need
4788 --a model def for that. It will be used by sum_numeric procedure.
4789
4790 aload_model_def ( p_component_id );
4791
4792 END IF;
4793
4794 l_return := generate_path ( l_node_id, t_exp_modelrefexplid ( j ), p_input_context, x_output_context );
4795
4796 --Store the generated parent in a local variable. This object will be used for each child.
4797
4798 IF ( h_psnid_psnodetype ( l_node_id ) <> h_psntypes ('bommodel')) THEN astore_local_variable ( 'var' ); END IF;
4799
4800 --Next on stack is either an instance quantifier, or a port that will require sum in case of
4801 --contributor. Also need to store.
4802
4803 IF ( l_return <> const_no_instances ) THEN astore_local_variable ( 'iq' ); END IF;
4804
4805 FOR i IN 1..t_children.COUNT LOOP
4806
4807 IF ( l_return <> const_no_instances ) THEN aload_local_variable ( 'iq' ); END IF;
4808
4809 IF ( h_psnid_psnodetype ( l_node_id ) = h_psntypes ('bommodel')) THEN
4810
4811 IF ( l_return = const_quantifier_created ) THEN
4812
4813 push_variable ( t_children ( i ).ps_node_id, 'IInstanceQuantifier');
4814
4815 ELSE
4816
4817 push_variable ( t_children ( i ).ps_node_id, 'IPortExprDef');
4818
4819 END IF;
4820
4821 ELSE
4822
4823 aload_local_variable ( 'var' );
4824 push_variable ( t_children ( i ).ps_node_id, 'ISingletonExprDef');
4825 emit_invokevirtual ('ISingletonExprDef.getVarRef(IExprDef)');
4826
4827 END IF;
4828
4829 IF ( t_psn_psnodetype ( t_children ( i ).expr_index ) IN ( h_psntypes ('bomoptionclass'), h_psntypes ('bomstandard'))) THEN
4830
4831 apply_bom_property ( h_quantities ( l_template_id ));
4832 IF ( l_return = const_resourcesum_required ) THEN emit_invokevirtual('IPortExprDef.sum(INumExprDef)'); END IF;
4833
4834 ELSE
4835
4836 --This is a bom port.
4837
4838 emit_dup ();
4839 emit_invokevirtual ('IPortExprDef.getType()');
4840 emit_invokevirtual ( h_quantities ( l_template_id ));
4841 emit_invokevirtual('IPortExprDef.sum(INumExprDef)');
4842
4843 END IF;
4844
4845 IF ( l_return = const_quantifier_created ) THEN emit_invokevirtual('IInstanceQuantifier.getExprFromInstance(IExprDef)'); END IF;
4846
4847 END LOOP;
4848
4849 --We need to sum up all the generated numeric expressions into a contributor term.
4850
4851 sum_numeric ( t_children.COUNT );
4852
4853 END IF;
4854 END generate_numeric_options;
4855 ----------------------------------------------------------------------------------
4856 -- Scope: compile_constraints
4857 PROCEDURE generate_options ( j IN PLS_INTEGER
4858 , p_input_context IN expression_context
4859 , x_output_context IN OUT NOCOPY expression_context
4860 ) IS
4861 BEGIN
4862
4863 IF ( numeric_context ( j, p_input_context.context_type )) THEN
4864
4865 generate_numeric_options ( j, NULL, FALSE, p_input_context, x_output_context );
4866
4867 ELSIF ( logical_context ( j, p_input_context.context_type )) THEN
4868
4869 generate_logical_options ( j, p_input_context, x_output_context );
4870
4871 ELSE
4872
4873 -- 'Unknown context occurred for options(). Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
4874 report_and_raise_rule_sys_warn(
4875 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_UNKNOWN_CONTEXT ),
4876 p_warning_location => 'generate_options' );
4877
4878 END IF;
4879 END generate_options;
4880 ----------------------------------------------------------------------------------
4881 --This procedure should be called when the generated expression is on top of stack.
4882 --Does not change the state of stack.
4883 -- Scope: compile_constraints
4884
4885 PROCEDURE set_reason_id IS
4886
4887 l_id NUMBER;
4888 l_text cz_localized_texts.localized_str%TYPE;
4889
4890 BEGIN
4891
4892 --reason_id for constraints, for which we call this procedure, cannot be null, so
4893 --it should be possible to remove this condition.
4894
4895 IF ( this_reason_id IS NOT NULL ) THEN
4896
4897 --Bug #6899574. Need to get the persistent id of localized text record.
4898
4899 SELECT persistent_intl_text_id, localized_str INTO l_id, l_text FROM cz_localized_texts
4900 WHERE deleted_flag = '0' AND language = USERENV ('LANG') AND intl_text_id = this_reason_id;
4901
4902 comment ( 'Set rule violation message: "' || l_text || '"' );
4903
4904 emit_dup ();
4905 push_long_constant ( l_id );
4906 emit_invokevirtual('IExprDef.setId(long)');
4907
4908 --Remove the null object from stack after a void method.
4909
4910 emit_pop ( 1 );
4911
4912 END IF;
4913
4914 EXCEPTION
4915 WHEN NO_DATA_FOUND THEN
4916
4917 report_and_raise_rule_sys_warn ( p_text => CZ_FCE_SW_NO_INTL_TEXT, p_warning_location => 'set_reason_id' );
4918
4919 END set_reason_id;
4920 ----------------------------------------------------------------------------------
4921 --This procedure should be called when the generated expression is on top of stack.
4922 --Does not change the state of stack.
4923 -- Scope: compile_constraints
4924 PROCEDURE add_constraint IS
4925
4926 l_method VARCHAR2(4000);
4927
4928 BEGIN
4929
4930 emit_effectivity ( 'ILogicExprDef', this_effective_from, this_effective_until, this_effective_usages );
4931
4932 l_method := 'IModelDef.add' || CASE NVL ( this_rule_class, h_ruleclasses ('constraint'))
4933 WHEN h_ruleclasses ('constraint') THEN 'Constraint'
4934 WHEN h_ruleclasses ('default') THEN 'DefaultDecision'
4935 WHEN h_ruleclasses ('search') THEN 'SearchDecision' END;
4936
4937 --Finish generation of the constraint and add it to the model def.
4938
4939 IF ( t_instancequantifiers.COUNT > 0 ) THEN
4940
4941 --There were instance quantifiers generated, so we need a ForAll and an extra root model
4942 --def to call ForAll on. But first we need to store the generated expression, which then
4943 --will be passed as the last argument to ForAll.
4944
4945 --Store the generated expression in a local variable. May be, a new instruction would be
4946 --better, something about storing in a register. We can use aload_local_variable here as
4947 --there is no way this local variable will be replaced with something else while we load
4948 --quantifiers.
4949
4950 --Note, that if forAll method had ILogicExprDef as the first parameter we'd just need to
4951 --swap it with the model def.
4952
4953 astore_local_variable ( 'exp' );
4954 aload_model_def ( p_component_id );
4955
4956 FOR i IN 1..t_instancequantifiers.COUNT LOOP
4957
4958 aload_quantifier ( t_instancequantifiers ( i ));
4959
4960 END LOOP;
4961
4962 CASE t_instancequantifiers.COUNT
4963
4964 WHEN 1 THEN
4965
4966 aload_local_variable ( 'exp' );
4967 emit_invokevirtual('IModelDef.forAll(IInstanceQuantifier, ILogicExprDef)');
4968
4969 WHEN 2 THEN
4970
4971 aload_local_variable ( 'exp' );
4972 emit_invokevirtual('IModelDef.forAll(IInstanceQuantifier, IInstanceQuantifier, ILogicExprDef)');
4973
4974 ELSE
4975
4976 create_array ( t_instancequantifiers.COUNT, h_javatypes ('IInstanceQuantifier'));
4977 populate_array ( t_instancequantifiers.COUNT );
4978 aload_local_variable ( 'exp' );
4979 emit_invokevirtual('IModelDef.forAll(IInstanceQuantifier[], ILogicExprDef)');
4980
4981 END CASE;
4982
4983 emit_invokevirtual( l_method || '(IForAllDef)');
4984
4985 ELSE
4986
4987 emit_invokevirtual( l_method || '(ILogicExprDef)');
4988
4989 END IF;
4990
4991 --Remove the null object from stack after a void method.
4992
4993 emit_pop ( 1 );
4994
4995 END add_constraint;
4996 ----------------------------------------------------------------------------------
4997 -- Scope: compile_constraints
4998 FUNCTION push_numeric_literal ( p_value IN NUMBER ) RETURN PLS_INTEGER IS
4999 BEGIN
5000
5001 IF ( ROUND ( p_value ) = p_value ) THEN
5002
5003 push_integer_constant ( p_value );
5004 RETURN h_datatypes ('integer');
5005
5006 ELSE
5007
5008 push_decimal_constant ( p_value );
5009 RETURN h_datatypes ('decimal');
5010
5011 END IF;
5012 END push_numeric_literal;
5013 ----------------------------------------------------------------------------------
5014 -- Scope: compile_constraints
5015 FUNCTION get_literal_value ( j IN PLS_INTEGER ) RETURN VARCHAR2 IS
5016
5017 l_val NUMBER;
5018
5019 BEGIN
5020
5021 IF ( t_exp_datatype ( j ) IN ( h_datatypes ('integer'), h_datatypes ('decimal'))) THEN
5022
5023 RETURN TO_CHAR ( t_exp_datanumvalue ( j ));
5024
5025 ELSIF ( t_exp_datatype ( j ) IN ( h_datatypes ('boolean'), h_datatypes ('text'))) THEN
5026
5027 RETURN t_exp_datavalue ( j );
5028
5029 ELSIF ( t_exp_datatype ( j ) IS NULL ) THEN
5030
5031 --#<temporary>
5032 --Developer does not populate data_type for constants in simple comparison rules.
5033 --Such constants can only be numeric, but the value is in data_value column.
5034 --It would be more consistent to have data_type column always populated for
5035 --literals and throw an inconsistency exception here.
5036
5037 l_val := TO_NUMBER ( NVL ( t_exp_datanumvalue ( j ), t_exp_datavalue ( j )));
5038
5039 --Need to populate data_type properly, because it is used to select the best signature.
5040
5041 t_exp_datatype ( j ) := CASE ROUND ( l_val ) WHEN l_val THEN h_datatypes ('integer') ELSE h_datatypes ('decimal') END;
5042 RETURN l_val;
5043
5044 ELSE
5045
5046 --#<should never happen>
5047 -- 'Invalid literal data type "^TYPE" found for the expression with the id ^EXPR_ID. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
5048 report_and_raise_rule_sys_warn(
5049 p_text => GET_NOT_TRANSLATED_TEXT(
5050 CZ_FCE_SW_INVALID_LIT_DTYPE,
5051 'TYPE', t_exp_datatype ( j ),
5052 'EXPR_ID', t_exp_exprnodeid ( j )),
5053 p_warning_location => 'get_literal_value' );
5054 RETURN NULL;
5055
5056 END IF;
5057 END get_literal_value;
5058 ----------------------------------------------------------------------------------
5059 -- Scope: compile_constraints
5060 PROCEDURE push_constant_expr ( p_value IN VARCHAR2, p_data_type IN NUMBER ) IS
5061 BEGIN
5062
5063 IF ( p_data_type NOT IN ( h_datatypes ('integer'), h_datatypes ('decimal'), h_datatypes ('boolean'))) THEN
5064
5065 --#<should never happen>
5066 -- 'Invalid constant data type "^TYPE" found. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
5067 report_and_raise_rule_sys_warn(
5068 p_text => GET_NOT_TRANSLATED_TEXT(
5069 CZ_FCE_SW_INVAL_CONST_DTYPE,
5070 'TYPE', p_data_type),
5071 p_warning_location => 'push_constant_expr' );
5072
5073 END IF;
5074
5075 IF ( p_value IS NULL ) THEN
5076 -- 'Null constant value occurred. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
5077 report_and_raise_rule_sys_warn(
5078 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_NULL_CONSTANT_VALUE),
5079 p_warning_location => 'push_constant_expr' );
5080
5081 END IF;
5082
5083 aload_model_def ( p_component_id );
5084
5085 CASE p_data_type
5086
5087 WHEN h_datatypes('integer') THEN
5088
5089 push_integer_constant ( TO_NUMBER ( p_value ));
5090 emit_invokevirtual('IModelDef.literal(int)');
5091
5092 WHEN h_datatypes('decimal') THEN
5093
5094 push_decimal_constant ( TO_NUMBER ( p_value ));
5095 emit_invokevirtual('IModelDef.literal(double)');
5096
5097 WHEN h_datatypes('boolean') THEN
5098
5099 emit_boolean ( p_value );
5100 emit_invokevirtual('IModelDef.literal(boolean)');
5101
5102 END CASE;
5103
5104 EXCEPTION
5105 WHEN INVALID_NUMBER THEN
5106
5107 --#<should never happen>
5108 -- 'Invalid number "^VALUE" found. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
5109 report_and_raise_rule_sys_warn(
5110 p_text => GET_NOT_TRANSLATED_TEXT(
5111 CZ_FCE_SW_INVALID_NUMBER,
5112 'VALUE', p_value ),
5113 p_warning_location => 'push_constant_expr:' || DBMS_UTILITY.FORMAT_ERROR_STACK ||
5114 '\nBack Trace:' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
5115
5116 END push_constant_expr;
5117 ----------------------------------------------------------------------------------
5118 -- Scope: compile_constraints
5119 PROCEDURE push_constant ( p_value IN VARCHAR2, p_data_type IN NUMBER ) IS
5120 BEGIN
5121
5122 IF ( p_value IS NULL ) THEN
5123 -- 'Null constant value occurred. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
5124 report_and_raise_rule_sys_warn(
5125 p_text => GET_NOT_TRANSLATED_TEXT(
5126 CZ_FCE_SW_NULL_CONSTANT_VALUE),
5127 p_warning_location => 'push_constant_expr' );
5128
5129
5130 END IF;
5131
5132 CASE p_data_type
5133
5134 WHEN h_datatypes ('integer') THEN
5135
5136 push_integer_constant ( TO_NUMBER ( p_value ));
5137
5138 WHEN h_datatypes ('decimal') THEN
5139
5140 push_decimal_constant ( TO_NUMBER ( p_value ));
5141
5142 WHEN h_datatypes ('boolean') THEN
5143
5144 emit_boolean ( p_value );
5145
5146 WHEN h_datatypes ('text') THEN
5147
5148 push_string_constant ( p_value );
5149
5150 ELSE
5151
5152 --#<should never happen>
5153 -- 'Invalid constant data type "^TYPE" found. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
5154 report_and_raise_rule_sys_warn(
5155 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_INVAL_CONST_DTYPE ),
5156 p_warning_location => 'push_constant' );
5157
5158 END CASE;
5159
5160 EXCEPTION
5161 WHEN INVALID_NUMBER THEN
5162
5163 --#<should never happen>
5164 -- 'Invalid number "^VALUE" found. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
5165 report_and_raise_rule_sys_warn(
5166 p_text => GET_NOT_TRANSLATED_TEXT(
5167 CZ_FCE_SW_INVALID_NUMBER,
5168 'VALUE', p_value ),
5169 p_warning_location => 'push_constant:' || DBMS_UTILITY.FORMAT_ERROR_STACK ||
5170 '\nBack Trace:' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
5171
5172 END push_constant;
5173 ----------------------------------------------------------------------------------
5174 -- Scope: compile_constraints
5175 PROCEDURE generate_constant ( j IN PLS_INTEGER ) IS
5176
5177 l_template_id NUMBER := t_exp_templateid ( j );
5178
5179 BEGIN
5180
5181 IF ( l_template_id NOT IN ( h_mathconstants ('e'), h_mathconstants ('pi'))) THEN
5182 -- 'Mathematical operator is not implemented for template_id "^TEMPL_ID". Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
5183 report_and_raise_rule_sys_warn(
5184 p_text => GET_NOT_TRANSLATED_TEXT(
5185 CZ_FCE_SW__NO_MATH_CONST,
5186 'TEMPL_ID', l_template_id ),
5187 p_warning_location => 'generate_constant' );
5188 END IF;
5189
5190 emit_constant ( l_template_id );
5191
5192 END generate_constant;
5193 ----------------------------------------------------------------------------------
5194 -- Scope: compile_constraints
5195 PROCEDURE generate_literal ( j IN PLS_INTEGER
5196 , p_value IN VARCHAR2
5197 , p_data_type IN NUMBER
5198 , p_input_context IN expression_context
5199 , x_output_context IN OUT NOCOPY expression_context ) IS
5200
5201 l_expr_id VARCHAR2(4000);
5202 l_index PLS_INTEGER;
5203 l_count PLS_INTEGER;
5204
5205 l_template_id NUMBER;
5206
5207 BEGIN
5208
5209 IF ( p_input_context.context_type = const_context_selection ) THEN
5210
5211 --This literal partitipates in an expression involving Selection() with a text
5212 --property. We just need to populate data structures that will be used in the
5213 --Selection() generation.
5214
5215 l_count := s_.COUNT + 1;
5216
5217 s_( l_count ) := 1;
5218 o_( l_count )( 1 ) := NULL; --this value is not used.
5219 t_( l_count )( 1 )( 1 ) := p_value;
5220
5221 RETURN;
5222
5223 END IF;
5224
5225 IF ( t_exp_exprparentid ( j ) IS NULL ) THEN
5226
5227 push_constant_expr ( p_value, p_data_type );
5228 RETURN;
5229
5230 END IF;
5231
5232 l_expr_id := TO_CHAR ( t_exp_exprparentid ( j ));
5233 l_index := h_exprid_backindex ( l_expr_id );
5234
5235 l_template_id := t_exp_templateid ( l_index );
5236
5237 IF ( p_data_type IN ( h_datatypes ('integer'), h_datatypes ('decimal'))) THEN
5238
5239 IF ( TO_NUMBER ( p_value ) = 1 AND l_template_id IN ( h_templates ('multiply'), h_templates ('div'))) THEN
5240
5241 --#<optimization>
5242 --The literal is an operand to mutliplication or division, and its value is 1.
5243
5244 x_output_context.context_type := const_context_literal;
5245 RETURN;
5246
5247 END IF;
5248 END IF;
5249
5250 --#<optimization>
5251 --We need to convert the literal to expression if
5252 -- it is the first operand of an operator;
5253 -- it is the only operand;
5254 -- it is any operand of 'array' operators.
5255 --These are not exact conditions and can be enhanced.
5256
5257 IF ( t_exp_seqnbr ( j ) = 1 OR
5258 h_exprid_numberofchildren ( l_expr_id ) = 1 OR
5259 h_operators_3.EXISTS ( l_template_id )
5260 ) THEN
5261
5262 push_constant_expr ( p_value, p_data_type );
5263
5264 ELSE
5265
5266 push_constant ( p_value, p_data_type );
5267 x_output_context.context_type := const_context_constant;
5268
5269 END IF;
5270 END generate_literal;
5271 ----------------------------------------------------------------------------------
5272 -- Scope: compile_constraints
5273 PROCEDURE invoke_operator2 ( p_template_id IN PLS_INTEGER, p_rhs_index IN PLS_INTEGER, p_input_context IN expression_context ) IS
5274 BEGIN
5275
5276 IF ( p_input_context.context_type = const_context_constant OR t_exp_exprtype ( p_rhs_index ) = h_exprtypes ('literal')) THEN
5277
5278 --The RHS operand is a literal or has been evaluated to a literal.
5279 --Select the best signature for the method to call.
5280
5281 IF ( t_exp_datatype ( p_rhs_index ) = h_datatypes ('integer')) THEN
5282
5283 emit_invokevirtual ( h_operators_2_int ( p_template_id ));
5284
5285 ELSIF ( t_exp_datatype ( p_rhs_index ) = h_datatypes ('decimal')) THEN
5286
5287 emit_invokevirtual ( h_operators_2_double ( p_template_id ));
5288
5289 ELSIF ( t_exp_datatype ( p_rhs_index ) = h_datatypes ('boolean')) THEN
5290
5291 emit_invokevirtual ( h_operators_2_boolean ( p_template_id ));
5292
5293 ELSE
5294
5295 emit_invokevirtual ( h_operators_2 ( p_template_id ));
5296
5297 END IF;
5298
5299 ELSE
5300
5301 emit_invokevirtual ( h_operators_2 ( p_template_id ));
5302
5303 END IF;
5304 END invoke_operator2;
5305 ----------------------------------------------------------------------------------
5306 -- Scope: compile_constraints
5307 PROCEDURE invoke_operator3 ( p_template_id IN PLS_INTEGER, p_count IN PLS_INTEGER, p_type IN VARCHAR2 ) IS
5308 BEGIN
5309
5310 --Parameters are on stack, create the array.
5311
5312 create_array ( p_count, h_javatypes ( p_type ));
5313 populate_array ( p_count );
5314
5315 --To call the method, we need a model def. We have to push it now and swap with
5316 --the array of parameters. We could not push the model def before generation of
5317 --parameters, for example: AnyTrue(F.Options()) - only when we generate Options
5318 --we will have the correct number of children of AnyTrue.
5319
5320 aload_model_def ( p_component_id );
5321 emit_swap ();
5322 emit_invokevirtual ( h_operators_3 ( p_template_id ));
5323
5324 END invoke_operator3;
5325 ----------------------------------------------------------------------------------
5326 -- Scope: compile_constraints
5327 PROCEDURE invoke_anyalltrue ( p_template_id IN PLS_INTEGER, p_count IN PLS_INTEGER, p_parent_id IN NUMBER DEFAULT 0 ) IS
5328 BEGIN
5329
5330 --#<optimization>
5331 --If there is only one actual operand, we don't need to do anything.
5332
5333 --Bug #6979696. Default and Search decision can have this operator on the root
5334 --level, in which case we need to apply it because we need to call addDecision
5335 --on the result. In many cases when we call this procedure we know it is not a
5336 --decision, so we don't have to specify the p_parent_id.
5337
5338 IF ( p_count < 2 AND p_parent_id IS NOT NULL ) THEN RETURN; END IF;
5339
5340 IF ( p_count = 2 ) THEN
5341
5342 --If there are two parameters, use Or/And instead.
5343
5344 emit_invokevirtual ( h_operators_3_opt ( p_template_id ));
5345
5346 ELSE
5347
5348 invoke_operator3 ( p_template_id, p_count, 'ILogicExprDef' );
5349
5350 END IF;
5351 END invoke_anyalltrue;
5352 ----------------------------------------------------------------------------------
5353 -- Scope: compile_constraints
5354 FUNCTION get_property_id ( j IN PLS_INTEGER ) RETURN NUMBER IS
5355
5356 l_type PLS_INTEGER;
5357
5358 BEGIN
5359
5360 IF ( t_exp_exprtype ( j ) IN ( h_exprtypes ('property'), h_exprtypes ('literal'))) THEN
5361
5362 h_propertyid_type ( TO_CHAR ( t_exp_propertyid ( j ))) := h_exprtypes ('property');
5363 RETURN t_exp_propertyid ( j );
5364
5365 ELSIF ( t_exp_exprtype ( j ) = h_exprtypes ('systemproperty')) THEN
5366
5367 h_propertyid_type ( TO_CHAR ( t_exp_templateid ( j ))) := h_exprtypes ('systemproperty');
5368 RETURN t_exp_templateid ( j );
5369
5370 ELSIF ( t_exp_exprtype ( j ) = h_exprtypes ('argument')) THEN
5371
5372 --In case of statement ForAll rule, iterator can participate in the where clause without
5373 --any property applied. We emulate this as non-existant system property with property_id
5374 --and data_type equal to the data type of the context.
5375
5376 l_type := get_context_type ( j );
5377
5378 h_propertyid_type ( TO_CHAR ( l_type )) := h_exprtypes ('systemproperty');
5379 RETURN l_type;
5380
5381 ELSE
5382 -- 'No property id found for the expression id "^EXPR_ID". Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
5383 report_and_raise_rule_sys_warn(
5384 p_text => GET_NOT_TRANSLATED_TEXT(
5385 CZ_FCE_SW_NO_PROP_ID_EXPR_ID,
5386 'EXPR_ID', TO_CHAR ( t_exp_exprnodeid ( j )) ),
5387 p_warning_location => 'get_property_id');
5388 RETURN NULL;
5389
5390 END IF;
5391 END get_property_id;
5392 ----------------------------------------------------------------------------------
5393 -- Scope: compile_constraints
5394 FUNCTION get_property_type ( p_property_id IN NUMBER ) RETURN PLS_INTEGER IS
5395
5396 l_property_id VARCHAR2(4000) := TO_CHAR ( p_property_id );
5397
5398 BEGIN
5399
5400 IF ( NOT h_propertyid_type.EXISTS ( l_property_id )) THEN
5401 -- 'No property type found for the property id "^PROP_ID". Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
5402 report_and_raise_rule_sys_warn(
5403 p_text => GET_NOT_TRANSLATED_TEXT(
5404 CZ_FCE_SW_NO_TYPE_FOR_PROP_ID,
5405 'PROP_ID', l_property_id ),
5406 p_warning_location => 'get_property_type');
5407
5408 END IF;
5409
5410 RETURN h_propertyid_type ( l_property_id );
5411 END get_property_type;
5412 ----------------------------------------------------------------------------------
5413 -- Scope: compile_constraints
5414 PROCEDURE get_static_info ( p_property_id IN NUMBER
5415 , x_data_type IN OUT NOCOPY NUMBER
5416 ) IS
5417
5418 l_property_id VARCHAR2(4000);
5419
5420 BEGIN
5421
5422 l_property_id := TO_CHAR ( p_property_id );
5423
5424 IF ( h_propertyid_datatype.EXISTS ( l_property_id )) THEN
5425
5426 x_data_type := h_propertyid_datatype ( l_property_id );
5427
5428 ELSE
5429
5430 IF ( p_property_id = h_templates ('name')) THEN
5431
5432 x_data_type := h_datatypes('text');
5433
5434 ELSIF ( p_property_id IN ( h_templates ('minvalue')
5435 , h_templates ('maxvalue')
5436 , h_templates ('minquantity')
5437 , h_templates ('maxquantity')
5438 , h_templates ('minselected')
5439 , h_templates ('maxselected')
5440 )
5441 ) THEN
5442
5443 x_data_type := h_datatypes ('decimal');
5444
5445 ELSIF ( p_property_id IN ( h_datatypes ('decimal')
5446 , h_datatypes ('boolean')
5447 , h_datatypes ('text')
5448 )
5449 ) THEN
5450
5451 --Case of iterator without any properties in the where clause of a statement ForAll.
5452
5453 x_data_type := p_property_id;
5454
5455 ELSIF ( p_property_id = h_templates ('description')) THEN
5456 -- System Property ^PROP_NAME is invalid in WHERE clause of a COMPATIBLE or FORALL operator because it is translatable. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
5457 report_and_raise_rule_warning(
5458 CZ_UTILS.GET_TEXT(CZ_FCE_W_DESCRIPTION_IN_WHERE,
5459 'PROP_NAME','description',
5460 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
5461 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path)),
5462 'get_static_info'
5463 );
5464
5465 ELSE
5466
5467 -- System Property ^PROPERTY_NAME is invalid in WHERE clause of
5468 -- COMPATIBLE or FORALL operator because its value is not static at runtime.
5469 -- Rule "^RULE_NAME" in the Model "^MODEL_NAME" ignored.'
5470
5471 report_and_raise_rule_warning(
5472 CZ_UTILS.GET_TEXT(CZ_FCE_W_PROPERTY_NOT_STATIC,
5473 'PROPERTY_NAME',CZ_FCE_COMPILE_UTILS.GET_PROPERTY_PATH(p_property_id),
5474 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
5475 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path)),
5476 'get_static_info'
5477 );
5478
5479 END IF;
5480
5481 h_propertyid_datatype ( l_property_id ) := x_data_type;
5482
5483 END IF;
5484 END get_static_info;
5485 ----------------------------------------------------------------------------------
5486 -- Scope: compile_constraints
5487 FUNCTION get_static_value ( p_property_id IN NUMBER
5488 , p_node_id IN NUMBER
5489 )
5490 RETURN VARCHAR2 IS
5491
5492 l_key VARCHAR2(4000);
5493 l_node_id VARCHAR2(4000);
5494 l_property_id VARCHAR2(4000);
5495
5496 l_value VARCHAR2(4000);
5497 l_index PLS_INTEGER;
5498
5499 BEGIN
5500
5501 l_node_id := TO_CHAR ( p_node_id );
5502 l_property_id := TO_CHAR ( p_property_id );
5503
5504 l_key := l_node_id || '-' || l_property_id;
5505
5506 IF ( h_psnid_propertyid_value.EXISTS ( l_key )) THEN
5507
5508 RETURN h_psnid_propertyid_value ( l_key );
5509
5510 END IF;
5511
5512 l_index := h_psnid_backindex ( l_node_id );
5513
5514 IF ( p_property_id = h_templates ('name')) THEN
5515
5516 l_value := t_psn_name ( l_index );
5517
5518 ELSIF ( p_property_id IN ( h_templates ('minvalue')
5519 , h_templates ('minquantity')
5520 , h_templates ('minselected')
5521 )
5522 ) THEN
5523
5524 l_value := t_psn_minimum ( l_index );
5525
5526 ELSIF ( p_property_id IN ( h_templates ('maxvalue')
5527 , h_templates ('maxquantity')
5528 , h_templates ('maxselected')
5529 )
5530 ) THEN
5531
5532 l_value := t_psn_maximum ( l_index );
5533
5534 ELSE
5535 -- 'Property with the template id "^PROP_ID" is not static. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
5536 report_and_raise_rule_sys_warn(
5537 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_NOT_STATIC_PROPERTY,
5538 'PROP_ID', l_property_id ),
5539 p_warning_location => 'get_static_value');
5540 END IF;
5541
5542 h_psnid_propertyid_value ( l_key ) := l_value;
5543 RETURN l_value;
5544
5545 END get_static_value;
5546 ----------------------------------------------------------------------------------
5547 PROCEDURE get_user_info ( p_property_id IN NUMBER
5548 , x_data_type IN OUT NOCOPY NUMBER
5549 , x_def_value IN OUT NOCOPY VARCHAR2
5550 ) IS
5551
5552 l_property_id VARCHAR2(4000);
5553
5554 BEGIN
5555
5556 l_property_id := TO_CHAR ( p_property_id );
5557
5558 IF ( h_propertyid_datatype.EXISTS ( l_property_id )) THEN
5559
5560 x_data_type := h_propertyid_datatype ( l_property_id );
5561 x_def_value := h_propertyid_defvalue ( l_property_id );
5562
5563 ELSE
5564
5565 SELECT NVL( TO_CHAR ( def_num_value ), def_value ), data_type INTO x_def_value, x_data_type
5566 FROM cz_properties
5567 WHERE property_id = p_property_id
5568 AND deleted_flag = '0';
5569
5570 h_propertyid_datatype ( l_property_id ) := x_data_type;
5571 h_propertyid_defvalue ( l_property_id ) := x_def_value;
5572
5573 END IF;
5574 END get_user_info;
5575 ----------------------------------------------------------------------------------
5576 -- Scope: compile_constraints
5577 FUNCTION get_user_value ( p_property_id IN NUMBER
5578 , p_node_id IN NUMBER
5579 , p_expl_id IN NUMBER
5580 , p_item_id IN NUMBER
5581 )
5582 RETURN VARCHAR2 IS
5583
5584 l_def_value VARCHAR2(4000);
5585 l_data_type NUMBER;
5586 l_key VARCHAR2(4000);
5587 l_tab type_varchar4000_table;
5588
5589 l_node_id VARCHAR2(4000);
5590 l_property_id VARCHAR2(4000);
5591
5592 BEGIN
5593
5594 l_node_id := TO_CHAR ( p_node_id );
5595 l_property_id := TO_CHAR ( p_property_id );
5596
5597 --#<temporary>
5598 --This key works well enough for properties, attached to structure nodes directly.
5599 --However, for properties attached through items it can result in excessive
5600 --quering as different ps nodes can have the same item id and hence the same
5601 --property value.
5602
5603 l_key := l_node_id || '-' || l_property_id;
5604
5605 IF ( h_psnid_propertyid_value.EXISTS ( l_key )) THEN
5606
5607 RETURN h_psnid_propertyid_value ( l_key );
5608
5609 END IF;
5610
5611 IF ( h_propertyid_defvalue.EXISTS ( l_property_id )) THEN
5612
5613 l_def_value := h_propertyid_defvalue ( l_property_id );
5614
5615 ELSE
5616
5617 get_user_info ( p_property_id, l_data_type, l_def_value );
5618
5619 END IF;
5620
5621 SELECT NVL ( TO_CHAR( data_num_value ), data_value ) BULK COLLECT INTO l_tab
5622 FROM cz_ps_prop_vals
5623 WHERE ps_node_id = p_node_id
5624 AND property_id = p_property_id
5625 AND deleted_flag = '0';
5626
5627 IF ( l_tab.COUNT = 0 AND p_item_id IS NOT NULL ) THEN
5628
5629 SELECT NVL( TO_CHAR ( property_num_value ), property_value ) BULK COLLECT INTO l_tab
5630 FROM cz_item_property_values
5631 WHERE property_id = p_property_id
5632 AND item_id = p_item_id
5633 AND deleted_flag = '0';
5634
5635 IF ( l_tab.COUNT = 0 )THEN
5636
5637 SELECT NULL BULK COLLECT INTO l_tab
5638 FROM cz_item_type_properties t, cz_item_masters m
5639 WHERE m.item_id = p_item_id
5640 AND m.deleted_flag = '0'
5641 AND t.deleted_flag = '0'
5642 AND t.property_id = p_property_id
5643 AND t.item_type_id = m.item_type_id;
5644
5645 END IF;
5646 END IF;
5647
5648 IF ( l_tab.COUNT = 0 ) THEN
5649 -- Property ^PROP_NAME is not defined for node ^NODE_NAME. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
5650 report_and_raise_rule_warning(
5651 p_text => CZ_UTILS.GET_TEXT( CZ_FCE_W_NO_PROPERTY_FOR_NODE,
5652 'PROP_NAME', CZ_FCE_COMPILE_UTILS.GET_PROPERTY_PATH(l_property_id),
5653 'NODE_NAME', CZ_FCE_COMPILE_UTILS.GET_NODE_PATH(p_node_id,
5654 ps_node_id_table_to_string(
5655 build_complete_path(p_node_id, p_expl_id) ) ),
5656 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
5657 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
5658 p_warning_location => 'get_user_value');
5659 END IF;
5660
5661 h_psnid_propertyid_value ( l_key ) := NVL ( l_tab ( 1 ), l_def_value );
5662
5663 IF ( h_psnid_propertyid_value ( l_key ) IS NULL ) THEN
5664 -- 'Property ^PROP_NAME has no value for node ^NODE_NAME. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
5665 report_and_raise_rule_warning(
5666 p_text => CZ_UTILS.GET_TEXT( CZ_FCE_W_PROPERTY_NULL_VALUE,
5667 'PROP_NAME', CZ_FCE_COMPILE_UTILS.GET_PROPERTY_PATH(l_property_id),
5668 'NODE_NAME', CZ_FCE_COMPILE_UTILS.GET_NODE_PATH(p_node_id,
5669 ps_node_id_table_to_string(
5670 build_complete_path(p_node_id, p_expl_id) ) ),
5671 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
5672 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
5673 p_warning_location => 'get_user_value');
5674
5675 END IF;
5676
5677 RETURN h_psnid_propertyid_value ( l_key );
5678
5679 END get_user_value;
5680 ----------------------------------------------------------------------------------
5681 PROCEDURE get_property_info ( p_property_id IN NUMBER
5682 , x_data_type IN OUT NOCOPY NUMBER
5683 , x_def_value IN OUT NOCOPY VARCHAR2
5684 ) IS
5685 BEGIN
5686
5687 IF ( get_property_type ( p_property_id ) = h_exprtypes ('property')) THEN
5688
5689 get_user_info ( p_property_id, x_data_type, x_def_value );
5690
5691 ELSE
5692
5693 get_static_info ( p_property_id, x_data_type );
5694
5695 END IF;
5696 END get_property_info;
5697 ----------------------------------------------------------------------------------
5698 FUNCTION get_property_value ( p_property_id IN NUMBER
5699 , p_node_id IN NUMBER
5700 , p_expl_id IN NUMBER
5701 )
5702 RETURN VARCHAR2 IS
5703 BEGIN
5704
5705 IF ( get_property_type ( p_property_id ) = h_exprtypes ('property')) THEN
5706
5707 RETURN get_user_value ( p_property_id, p_node_id, p_expl_id, t_psn_itemid ( h_psnid_backindex ( TO_CHAR ( p_node_id ))));
5708
5709 ELSE
5710
5711 RETURN get_static_value ( p_property_id, p_node_id );
5712
5713 END IF;
5714 END get_property_value;
5715 ----------------------------------------------------------------------------------
5716 --For operators with one operand (totext, not, neg), p_left_operand is used.
5717 -- Scope: compile_constraints
5718 FUNCTION parse_operator ( p_left_operand IN VARCHAR2
5719 , p_operator IN PLS_INTEGER
5720 , p_right_operand IN VARCHAR2
5721 ) RETURN VARCHAR2 IS
5722 BEGIN
5723
5724 IF ( p_operator IN
5725 ( h_templates ('and')
5726 , h_templates ('or')
5727 , h_templates ('equals')
5728 , h_templates ('notequals')
5729 , h_templates ('gt')
5730 , h_templates ('lt')
5731 , h_templates ('ge')
5732 , h_templates ('le')
5733 , h_templates ('add')
5734 , h_templates ('subtract')
5735 , h_templates ('multiply')
5736 , h_templates ('div')
5737 , h_templates('textequals')
5738 , h_templates('textnotequals')
5739 )) THEN
5740
5741 RETURN '(' || p_left_operand || h_template_tokens ( p_operator ) || p_right_operand || ')';
5742
5743 ELSIF ( p_operator IN
5744 ( h_templates ('totext')
5745 , h_templates ('not')
5746 , h_templates ('neg')
5747 )) THEN
5748
5749 RETURN '(' || h_template_tokens ( p_operator ) || '(' || p_left_operand || '))';
5750
5751 ELSIF ( p_operator = h_templates ('doesnotbeginwith')) THEN
5752
5753 RETURN '(' || p_left_operand || ' NOT LIKE ' || p_right_operand || '||''%'')';
5754
5755 ELSIF ( p_operator = h_templates ('doesnotendwith')) THEN
5756
5757 RETURN '(' || p_left_operand || ' NOT LIKE ''%''||' || p_right_operand || ')';
5758
5759 ELSIF ( p_operator = h_templates ('doesnotcontain')) THEN
5760
5761 RETURN '(' || p_left_operand || ' NOT LIKE ''%''||' || p_right_operand || '||''%'')';
5762
5763 ELSIF ( p_operator = h_templates ('notlike')) THEN
5764
5765 RETURN '(' || p_left_operand || ' NOT LIKE ' || p_right_operand || ')';
5766
5767 ELSIF ( p_operator = h_templates ('concatenate')) THEN
5768
5769 RETURN p_left_operand || '||' || p_right_operand;
5770
5771 ELSIF ( p_operator = h_templates ('beginswith')) THEN
5772
5773 RETURN '(' || p_left_operand || ' LIKE ' || p_right_operand || '||''%'')';
5774
5775 ELSIF ( p_operator = h_templates ('endswith')) THEN
5776
5777 RETURN '(' || p_left_operand || ' LIKE ''%''||' || p_right_operand || ')';
5778
5779 ELSIF ( p_operator = h_templates ('contains')) THEN
5780
5781 RETURN '(' || p_left_operand || ' LIKE ''%''||' || p_right_operand || '||''%'')';
5782
5783 ELSIF ( p_operator = h_templates ('like')) THEN
5784
5785 RETURN '(' || p_left_operand || ' LIKE ' || p_right_operand || ')';
5786
5787 ELSIF ( p_operator = h_templates ('matches')) THEN
5788
5789 RETURN '(' || p_left_operand || ' LIKE ' || p_right_operand || ')';
5790
5791 END IF;
5792 END parse_operator;
5793 ----------------------------------------------------------------------------------
5794 -- Scope: compile_constraints
5795 FUNCTION build_executable ( p_count IN PLS_INTEGER, p_parsed IN VARCHAR2 ) RETURN VARCHAR2 IS
5796
5797 l_open VARCHAR2(32000);
5798 l_body VARCHAR2(32000);
5799 l_close VARCHAR2(32000);
5800
5801 l_value VARCHAR2(4000);
5802
5803 BEGIN
5804
5805 FOR i IN 1..p_count LOOP
5806
5807 l_value := TO_CHAR ( i );
5808
5809 l_open := l_open || ' FOR i' || l_value || ' IN 1..cz_fce_compile.s_(' || l_value || ') LOOP';
5810 l_body := l_body || ' cz_fce_compile.c_.combinations(l)(' || l_value || '):=cz_fce_compile.o_(' || l_value || ')(i' || l_value || ');';
5811 l_close := l_close || 'END LOOP;';
5812
5813 END LOOP;
5814
5815 --Example of an executable block that will be constructed for the following WHERE clause
5816 --(passed in p_condition).
5817
5818 --#<optimization> See bug #6531346 for possible optimization.
5819
5820 --WHERE #x.Property("p1") = #y.Property("p2")
5821 -- AND #x.Property("p1") = #z.Property("p2")
5822 -- AND #z.Name() BEGINSWITH "abc"
5823 -- AND #x.Property("p3") = TRUE
5824 -- AND (2 = 2)
5825
5826 --Resulting code (note that parser has rewritten (2 = 2) as TRUE):
5827
5828 --DECLARE
5829 -- l PLS_INTEGER:=1;
5830 --BEGIN
5831 -- FOR i1 IN 1..cz_fce_compile.s_(1) LOOP
5832 -- FOR i2 IN 1..cz_fce_compile.s_(2) LOOP
5833 -- FOR i3 IN 1..cz_fce_compile.s_(3) LOOP
5834 -- IF((cz_fce_compile.n_(1)(i1)(1)=cz_fce_compile.n_(2)(i2)(2))AND
5835 -- (cz_fce_compile.n_(1)(i1)(1)=cz_fce_compile.n_(3)(i3)(2))AND
5836 -- (cz_fce_compile.t_(3)(i3)(3) LIKE 'abc%')AND
5837 -- (cz_fce_compile.b_(1)(i1)(4)=1)AND(TRUE))THEN
5838 -- cz_fce_compile.c_.combinations(l)(1):=cz_fce_compile.o_(1)(i1);
5839 -- cz_fce_compile.c_.combinations(l)(2):=cz_fce_compile.o_(2)(i2);
5840 -- cz_fce_compile.c_.combinations(l)(3):=cz_fce_compile.o_(3)(i3);
5841 -- l := l + 1;
5842 -- END IF;
5843 -- END LOOP;
5844 -- END LOOP;
5845 -- END LOOP;
5846 --END;
5847
5848 RETURN 'DECLARE l PLS_INTEGER:=1;BEGIN'
5849 || l_open ||
5850 ' IF(' || NVL ( p_parsed, 'TRUE' ) || ')THEN'
5851 || l_body ||
5852 'l:=l+1;END IF;'
5853 || l_close ||
5854 'END;';
5855 END;
5856 ----------------------------------------------------------------------------------
5857 -- Scope: compile_constraints
5858 PROCEDURE generate_user_property ( j IN PLS_INTEGER
5859 , p_input_context IN expression_context
5860 , x_output_context IN OUT NOCOPY expression_context ) IS
5861
5862 l_property_id NUMBER;
5863 l_data_type NUMBER;
5864 l_def_value VARCHAR2(4000);
5865 l_value VARCHAR2(4000);
5866 l_expr_id VARCHAR2(4000);
5867 l_index PLS_INTEGER;
5868
5869 l_input_context expression_context;
5870
5871 BEGIN
5872
5873 l_property_id := t_exp_propertyid ( h_exprid_childrenindex ( TO_CHAR ( t_exp_exprnodeid ( j ))));
5874 get_user_info ( l_property_id, l_data_type, l_def_value );
5875
5876 l_value := get_user_value ( l_property_id
5877 , t_exp_psnodeid ( j )
5878 , t_exp_modelrefexplid ( j )
5879 , t_psn_itemid ( h_psnid_backindex ( TO_CHAR ( t_exp_psnodeid ( j ))))
5880 );
5881
5882 IF ( l_data_type = h_datatypes('text')) THEN
5883
5884 IF ( numeric_context ( j, p_input_context.context_type )) THEN
5885
5886 --This property is used as a numeric property but has data type 'text', for example,
5887 --bom properties imported without data type resolution. In this case, all values of
5888 --this property are assumed to be convertible to numbers. If this is not true, this
5889 --will cause problems later in push_constant_expr where will be actually converted.
5890
5891 --We can add the check for number here, and also see if it is decimal or integer for
5892 --better resolution of data type.
5893
5894 l_data_type := h_datatypes ('decimal');
5895
5896 ELSE
5897
5898 --#<should never happen>
5899 -- 'Found property with the id "^PROP_ID" as text property. Rules cannot handle text properties. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
5900 report_and_raise_rule_sys_warn(
5901 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_NO_TEXT_PROP,
5902 'PROP_ID', l_property_id ),
5903 p_warning_location => 'generate_user_property');
5904
5905 END IF;
5906 END IF;
5907
5908 --#<problem>
5909 --Note that the input context of this procedure is not passed down to generate_literal.
5910 --The local context variable is not used in any other way, so it seems that it's been
5911 --created specifically for this purpose. Not sure if this was done intentionally, need
5912 --to keep an eye on it.
5913
5914 generate_literal ( j, l_value, l_data_type, l_input_context, x_output_context );
5915
5916 END generate_user_property;
5917 ----------------------------------------------------------------------------------
5918 -- Scope: compile_constraints
5919 PROCEDURE generate_selection_property ( j IN PLS_INTEGER
5920 , p_property_id IN NUMBER
5921 , p_input_context IN expression_context
5922 , x_output_context IN OUT NOCOPY expression_context
5923 ) IS
5924
5925 l_return PLS_INTEGER;
5926 l_index PLS_INTEGER;
5927
5928 l_is_bom BOOLEAN;
5929
5930 BEGIN
5931
5932 IF ( h_quantities.EXISTS ( p_property_id )) THEN
5933
5934 generate_numeric_options ( j, p_property_id, TRUE, p_input_context, x_output_context );
5935 RETURN;
5936
5937 END IF;
5938
5939 l_index := h_psnid_backindex ( TO_CHAR ( t_exp_psnodeid ( j )));
5940 l_is_bom := is_bom_node ( l_index );
5941
5942 l_return := generate_path ( t_exp_psnodeid ( j ), t_exp_modelrefexplid ( j ), p_input_context, x_output_context );
5943
5944 IF ( l_return = const_quantifier_created ) THEN
5945
5946 emit_invokevirtual('IInstanceQuantifier.getExprFromInstance(IExprDef)');
5947
5948 END IF;
5949
5950 --This procedure is called in generate_selection only when the property applied
5951 --to selection, is one of Quantity(), State() or Value(). In case of Value() we
5952 --just generate the node, which is already done above. So, here we only have to
5953 --generate State().
5954
5955 IF ( l_is_bom ) THEN
5956
5957 apply_bom_property ('IBomDef.getOCCardSet()');
5958
5959 END IF;
5960
5961 IF ( p_property_id = h_templates ('state')) THEN
5962
5963 any_option_selected ();
5964
5965 END IF;
5966
5967 IF ( l_return = const_resourcesum_required ) THEN
5968
5969 emit_invokevirtual('IPortExprDef.sum(INumExprDef)');
5970
5971 END IF;
5972 END generate_selection_property;
5973 ----------------------------------------------------------------------------------
5974 -- Scope: compile_constraints
5975 PROCEDURE generate_selection_object ( p_node_id IN NUMBER
5976 , p_expl_id IN NUMBER
5977 , p_data_type IN NUMBER
5978 , p_property_values IN type_numbertable_hashtable
5979 , p_input_context IN expression_context
5980 , x_output_context IN OUT NOCOPY expression_context
5981 ) IS
5982
5983 l_return PLS_INTEGER;
5984 l_count PLS_INTEGER;
5985 l_value VARCHAR2(4000);
5986
5987 BEGIN
5988
5989 IF ( p_property_values.COUNT > 2 ) THEN
5990
5991 --If there are more than two distinct property values, we will call 'sum' later,
5992 --and need model def for that.
5993
5994 aload_model_def ( p_component_id );
5995
5996 END IF;
5997
5998 l_return := generate_path ( p_node_id, p_expl_id, p_input_context, x_output_context );
5999
6000 IF ( h_psnid_detailedtype ( TO_CHAR ( p_node_id )) = h_psntypes ('optionfeature')) THEN
6001
6002 IF ( l_return = const_quantifier_created ) THEN emit_invokevirtual('IInstanceQuantifier.getExprFromInstance(IExprDef)'); END IF;
6003
6004 astore_local_variable ( 'var' );
6005
6006 l_value := p_property_values.FIRST;
6007
6008 WHILE ( l_value IS NOT NULL ) LOOP
6009
6010 l_count := p_property_values ( l_value ).COUNT;
6011 aload_local_variable ( 'var' );
6012
6013 FOR i IN 1..l_count LOOP
6014
6015 push_variable_name ( p_property_values ( l_value )( i ));
6016
6017 END LOOP;
6018
6019 IF ( l_count = 1 ) THEN
6020
6021 --Just one option, generate 'contains' instead of 'intersects'.
6022
6023 emit_invokevirtual ('ISetExprDef.contains(Object)');
6024
6025 ELSE
6026
6027 create_array ( l_count, h_javatypes ('Object'));
6028 populate_array ( l_count );
6029 emit_invokevirtual ('ISetExprDef.intersects(Object[])');
6030
6031 END IF;
6032
6033 --If the property value is 1, there is no need to multiply.
6034
6035 IF ( TO_NUMBER ( l_value ) <> 1 ) THEN
6036
6037 push_decimal_constant ( TO_NUMBER ( l_value ));
6038 emit_invokevirtual ( CASE p_data_type WHEN h_datatypes ('decimal') THEN 'INumExprDef.prod(double)' ELSE 'INumExprDef.prod(int)' END );
6039
6040 END IF;
6041
6042 l_value := p_property_values.NEXT ( l_value );
6043
6044 END LOOP;
6045
6046 ELSIF ( h_psnid_detailedtype ( TO_CHAR ( p_node_id )) = h_psntypes ('bomoptionclass')) THEN
6047
6048 astore_local_variable ( 'var' );
6049
6050 --If there is an instance quantifier, it is now on top of stack. Also need to store.
6051
6052 IF ( l_return = const_quantifier_created ) THEN astore_local_variable ( 'iq' ); END IF;
6053
6054 l_value := p_property_values.FIRST;
6055
6056 WHILE ( l_value IS NOT NULL ) LOOP
6057
6058 l_count := p_property_values ( l_value ).COUNT;
6059
6060 FOR i IN 1..l_count LOOP
6061
6062 IF ( l_return = const_quantifier_created ) THEN aload_local_variable ( 'iq' ); END IF;
6063 aload_local_variable ( 'var' );
6064
6065 push_variable ( p_property_values ( l_value )( i ), 'ISingletonExprDef');
6066 emit_invokevirtual ('ISingletonExprDef.getVarRef(IExprDef)');
6067
6068 apply_bom_logical_context ( p_property_values ( l_value )( i ), l_return );
6069
6070 END LOOP;
6071
6072 invoke_anyalltrue ( h_templates ('anytrue'), l_count );
6073
6074 --If the property value is 1, there is no need to multiply.
6075
6076 IF ( TO_NUMBER ( l_value ) <> 1 ) THEN
6077
6078 push_decimal_constant ( TO_NUMBER ( l_value ));
6079 emit_invokevirtual ( CASE p_data_type WHEN h_datatypes ('decimal') THEN 'INumExprDef.prod(double)' ELSE 'INumExprDef.prod(int)' END );
6080
6081 END IF;
6082
6083 l_value := p_property_values.NEXT ( l_value );
6084
6085 END LOOP;
6086
6087 ELSE
6088 -- '"Selection()" property is allowed only for Option Feature or BOM Option Class. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
6089 report_and_raise_rule_sys_warn(
6090 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_SELECT_PROP_NOTALLOW ),
6091 p_warning_location => 'generate_selection_object');
6092
6093 END IF;
6094
6095 sum_numeric ( p_property_values.COUNT );
6096
6097 END generate_selection_object;
6098 ----------------------------------------------------------------------------------
6099 -- Scope: compile_constraints
6100 PROCEDURE generate_text_comparison ( p_operator IN PLS_INTEGER
6101 , p_side IN PLS_INTEGER
6102 , p_input_context IN expression_context
6103 , x_output_context IN OUT NOCOPY expression_context
6104 ) IS
6105
6106 t_property_values type_numbertable_hashtable;
6107
6108 BEGIN
6109
6110 EXECUTE IMMEDIATE build_executable ( 2, parse_operator ( 'cz_fce_compile.t_(1)(i1)(1)', p_operator, 'cz_fce_compile.t_(2)(i2)(1)'));
6111
6112 IF ( p_side = 0 ) THEN
6113
6114 --There is no selection, both sides are text literals, just push either true or false.
6115
6116 push_constant_expr ( CASE c_.combinations.COUNT WHEN 0 THEN '0' ELSE '1' END, h_datatypes ('boolean'));
6117
6118 ELSE
6119
6120 --We populate the table in such a way, that the following procedure will just generate
6121 --intersect of all options or bom children. The key '1' is used so that this intersect
6122 --would not be multiplied by anything.
6123
6124 FOR i IN 1..c_.combinations.COUNT LOOP
6125
6126 t_property_values ( '1' )( i ) := c_.combinations ( i )( p_side ).ps_node_id;
6127
6128 END LOOP;
6129
6130 generate_selection_object ( c_.participants ( p_side ).ps_node_id
6131 , c_.participants ( p_side ).model_ref_expl_id
6132 , h_datatypes ('text')
6133 , t_property_values
6134 , p_input_context, x_output_context );
6135 END IF;
6136 END generate_text_comparison;
6137 ----------------------------------------------------------------------------------
6138 -- Scope: compile_constraints
6139 PROCEDURE generate_selection ( j IN PLS_INTEGER
6140 , p_property_id IN NUMBER
6141 , p_input_context IN expression_context
6142 , x_output_context IN OUT NOCOPY expression_context
6143 ) IS
6144
6145 l_property_id NUMBER := p_property_id;
6146 l_data_type NUMBER;
6147 l_value VARCHAR2(4000);
6148 l_count PLS_INTEGER;
6149
6150 l_text_property BOOLEAN := FALSE;
6151 l_side PLS_INTEGER;
6152
6153 t_children type_iteratornode_table;
6154 t_property_values type_numbertable_hashtable;
6155
6156 BEGIN
6157
6158 IF ( t_exp_psnodeid ( j ) IS NULL ) THEN
6159 -- '"Selection()" property is allowed only for Option Feature or BOM Option Class. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
6160 report_and_raise_rule_sys_warn(
6161 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_SELECT_PROP_NOTALLOW ),
6162 p_warning_location => 'generate_selection');
6163
6164 END IF;
6165
6166 IF ( l_property_id IS NULL ) THEN
6167
6168 --No explicitly specified property, derive one from the context.
6169
6170 IF ( logical_context ( j, p_input_context.context_type )) THEN
6171
6172 l_property_id := h_templates ('state');
6173
6174 ELSIF ( numeric_context ( j, p_input_context.context_type )) THEN
6175
6176 l_property_id := h_templates ('quantity');
6177
6178 ELSE
6179 -- 'Invalid context found for applying default property. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
6180 report_and_raise_rule_sys_warn(
6181 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_DEFPROP_INVAL_CTX ),
6182 p_warning_location => 'generate_selection');
6183
6184 END IF;
6185
6186 h_propertyid_type ( TO_CHAR ( l_property_id )) := h_exprtypes ('systemproperty');
6187
6188 END IF;
6189
6190 IF ( h_quantities.EXISTS ( l_property_id ) OR l_property_id IN ( h_templates ('state'), h_templates ('value'))) THEN
6191
6192 generate_selection_property ( j, l_property_id, p_input_context, x_output_context );
6193 RETURN;
6194
6195 ELSIF ( l_property_id IN ( h_templates ('name'), h_templates ('description'))) THEN
6196
6197 get_static_info ( l_property_id, l_data_type );
6198
6199 ELSIF ( get_property_type ( l_property_id ) = h_exprtypes ('property')) THEN
6200
6201 get_user_info ( l_property_id, l_data_type, l_value );
6202
6203 ELSE
6204 -- 'Invalid system property is used with the "Selection()" operator. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
6205 report_and_raise_rule_sys_warn(
6206 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_INVAL_SPROP_SELECT ),
6207 p_warning_location => 'generate_selection');
6208
6209 END IF;
6210
6211 t_children := explode_node_children ( t_exp_psnodeid ( j ), t_exp_modelrefexplid ( j ), TRUE );
6212
6213 IF ( l_data_type = h_datatypes ('text') OR p_input_context.context_type = const_context_selection ) THEN
6214
6215 --This will be 'text' selection, prepare the data structures.
6216
6217 l_side := s_.COUNT + 1;
6218 s_( l_side ) := t_children.COUNT;
6219
6220 c_.participants ( l_side ).ps_node_id := t_exp_psnodeid ( j );
6221 c_.participants ( l_side ).model_ref_expl_id := t_exp_modelrefexplid ( j );
6222
6223 l_text_property := TRUE;
6224
6225 END IF;
6226
6227 --All distinct property values are keys to the tables of all options that have these values.
6228
6229 FOR i IN 1..t_children.COUNT LOOP
6230
6231 l_value := get_property_value ( l_property_id, t_children ( i ).ps_node_id, t_children ( i ).model_ref_expl_id );
6232
6233 IF ( l_value IS NULL ) THEN
6234 -- 'Property ^PROP_NAME has no value for node ^NODE_NAME. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
6235 report_and_raise_rule_warning(
6236 p_text => CZ_UTILS.GET_TEXT( CZ_FCE_W_PROPERTY_NULL_VALUE,
6237 'PROP_NAME', CZ_FCE_COMPILE_UTILS.GET_PROPERTY_PATH(l_property_id),
6238 'NODE_NAME', CZ_FCE_COMPILE_UTILS.GET_NODE_PATH(t_children ( i ).ps_node_id,
6239 ps_node_id_table_to_string(
6240 build_complete_path(t_children ( i ).ps_node_id, t_children ( i ).model_ref_expl_id) ) ),
6241 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
6242 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
6243 p_warning_location => 'generate_selection');
6244
6245 END IF;
6246
6247 IF ( l_text_property ) THEN
6248
6249 --Populate the data structures that will be used for generation.
6250
6251 o_( l_side )( i ).ps_node_id := t_children ( i ).ps_node_id;
6252 o_( l_side )( i ).model_ref_expl_id := t_children ( i ).model_ref_expl_id;
6253
6254 t_( l_side )( i )( 1 ) := l_value;
6255
6256 ELSE
6257
6258 IF ( NOT t_property_values.EXISTS ( l_value )) THEN
6259
6260 t_property_values ( l_value )( 1 ) := t_children ( i ).ps_node_id;
6261
6262 ELSE
6263
6264 l_count := t_property_values ( l_value ).COUNT + 1;
6265 t_property_values ( l_value )( l_count ) := t_children ( i ).ps_node_id;
6266
6267 END IF;
6268 END IF;
6269 END LOOP;
6270
6271 IF ( NOT l_text_property ) THEN
6272
6273 --Generate the 'numeric' selection object.
6274
6275 generate_selection_object ( t_exp_psnodeid ( j )
6276 , t_exp_modelrefexplid ( j )
6277 , l_data_type
6278 , t_property_values
6279 , p_input_context, x_output_context );
6280
6281 END IF;
6282 END generate_selection;
6283 ----------------------------------------------------------------------------------
6284 -- Scope: compile_constraints
6285 -- Returns the data type of the given signature argument.
6286
6287 FUNCTION get_signature_arg_info ( p_arg_index IN NUMBER
6288 , p_signature_id IN NUMBER
6289 , x_mutable IN OUT NOCOPY VARCHAR2
6290 , x_collection IN OUT NOCOPY VARCHAR2
6291 ) RETURN NUMBER IS
6292
6293 l_data_type cz_signature_arguments.data_type%TYPE;
6294
6295 BEGIN
6296
6297 SELECT data_type, mutable_flag, collection_flag INTO l_data_type, x_mutable, x_collection
6298 FROM cz_signature_arguments
6299 WHERE deleted_flag = '0'
6300 AND argument_signature_id = p_signature_id
6301 AND argument_index = p_arg_index;
6302
6303 RETURN l_data_type;
6304
6305 EXCEPTION
6306 WHEN OTHERS THEN
6307
6308 report_and_raise_rule_sys_warn (
6309 p_text => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SW_RE_ENSARG_NO_DTYPE,
6310 'ARG_IX', p_arg_index,
6311 'SIGNATURE_ID', p_signature_id ),
6312 p_warning_location => 'get_signature_arg_info');
6313
6314 RETURN NULL;
6315
6316 END get_signature_arg_info;
6317 ---------------------------------------------------------------------------------------
6318 -- Scope: compile_constraints
6319 -- Returns TRUE when the given property associated with the given node id is valid, otherwise
6320 -- returns FALSE.
6321
6322 FUNCTION is_valid_property ( j IN PLS_INTEGER
6323 , p_ps_node_id IN NUMBER
6324 , p_property_id IN NUMBER
6325 ) RETURN BOOLEAN IS
6326
6327 l_null PLS_INTEGER;
6328 l_data_type cz_signature_arguments.data_type%TYPE;
6329 l_mutable cz_signature_arguments.mutable_flag%TYPE;
6330 l_collection cz_signature_arguments.collection_flag%TYPE;
6331
6332 l_key VARCHAR2(4000);
6333
6334 BEGIN
6335
6336 l_key := TO_CHAR ( p_ps_node_id ) || ':' || TO_CHAR ( p_property_id );
6337
6338 IF ( NOT h_psnid_propid_isvalid.EXISTS ( l_key )) THEN
6339
6340 IF ( t_exp_paramindex ( j ) IS NULL OR t_exp_paramsignatureid ( j ) IS NULL ) THEN
6341
6342 --Some of the upgraded rules may not have param_index and param_signature_id populated. However, upgraded
6343 --rules are not real statement rules, so they are not supposed to have any user error in them and in this
6344 --case the verification is not required.
6345
6346 h_psnid_propid_isvalid ( l_key ) := TRUE;
6347
6348 ELSE
6349
6350 BEGIN
6351
6352 l_data_type := get_signature_arg_info ( t_exp_paramindex ( j ), t_exp_paramsignatureid ( j ), l_mutable, l_collection );
6353
6354 SELECT NULL INTO l_null
6355 FROM cz_rul_typedpsn_v psn,
6356 cz_conversion_rels_v cnv,
6357 cz_system_property_rels_v rel,
6358 cz_system_properties_v sys,
6359 cz_conversion_rels_v cnv2
6360 WHERE psn.detailed_type_id = cnv.object_type
6361 AND cnv.subject_type = rel.subject_type
6362 AND rel.object_type = sys.rule_id
6363 AND rel.rel_type_code = 'SYS'
6364 AND sys.data_type = cnv2.object_type
6365 AND psn.ps_node_id = p_ps_node_id
6366 AND sys.rule_id = p_property_id
6367 AND sys.mutable_flag >= l_mutable
6368 --Note: Collection flag filter is removed, to allow rules like AddsTo(OptionFeature.options(), Total).
6369 -- AND sys.collection_flag <= l_collection
6370 AND cnv2.subject_type = l_data_type;
6371
6372 h_psnid_propid_isvalid ( l_key ) := TRUE;
6373
6374 EXCEPTION
6375 WHEN NO_DATA_FOUND THEN
6376 h_psnid_propid_isvalid ( l_key ) := FALSE;
6377 WHEN TOO_MANY_ROWS THEN
6378 h_psnid_propid_isvalid ( l_key ) := TRUE;
6379 WHEN OTHERS THEN
6380 RAISE;
6381 END;
6382 END IF;
6383 END IF;
6384
6385 RETURN h_psnid_propid_isvalid ( l_key );
6386
6387 END is_valid_property;
6388 ---------------------------------------------------------------------------------------
6389 -- Scope: compile_constraints
6390 PROCEDURE generate_structure_node ( j IN PLS_INTEGER
6391 , p_input_context IN expression_context
6392 , x_output_context IN OUT NOCOPY expression_context ) IS
6393
6394 l_expr_id VARCHAR2(4000);
6395 l_property_id NUMBER;
6396 l_index PLS_INTEGER;
6397 l_target_key VARCHAR2(4000);
6398
6399 BEGIN
6400
6401 IF ( p_input_context.context_type = const_context_target ) THEN
6402
6403 --This has been moved here from generate_path because when the target exists, we need
6404 --to just populate the output context and exit and not apply any context that is done
6405 --usually after generate_path (for example, see generate_node).
6406
6407 --In general, this key should contain more information about the target and the rule,
6408 --including rule's effecitivity and usage, and target's properties.
6409
6410 l_target_key := TO_CHAR ( t_exp_psnodeid ( j )) || ':' || TO_CHAR ( t_exp_modelrefexplid ( j ));
6411
6412 IF ( h_acc_targets.EXISTS ( l_target_key )) THEN
6413
6414 --Target has been generated before, just return. Context is changed to generic to
6415 --indicate that.
6416
6417 x_output_context.context_type := const_context_generic;
6418 x_output_context.context_num_data := h_acc_targets ( l_target_key );
6419
6420 RETURN;
6421 END IF;
6422 END IF;
6423
6424 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
6425
6426 IF ( NOT h_exprid_childrenindex.EXISTS ( l_expr_id )) THEN
6427
6428 generate_node ( j, p_input_context, x_output_context );
6429
6430 ELSE
6431
6432 l_index := h_exprid_childrenindex ( l_expr_id );
6433
6434 IF ( t_exp_exprtype ( l_index ) = h_exprtypes ('property')) THEN
6435
6436 generate_user_property ( j, p_input_context, x_output_context );
6437
6438 ELSIF ( t_exp_templateid ( l_index ) = h_templates ('selection')) THEN
6439
6440 l_index := l_index + 1;
6441
6442 IF ( t_exp_exprparentid.EXISTS ( l_index ) AND t_exp_exprparentid ( l_index ) = t_exp_exprnodeid ( j )) THEN
6443
6444 l_property_id := get_property_id ( l_index );
6445
6446 END IF;
6447
6448 generate_selection ( j, l_property_id, p_input_context, x_output_context );
6449
6450 ELSE
6451
6452 l_property_id := t_exp_templateid ( l_index );
6453
6454 IF ( l_property_id IN ( h_templates ('mininstances'), h_templates ('maxinstances')) OR
6455 ( NOT is_valid_property ( j, t_exp_psnodeid ( j ), l_property_id ))) THEN
6456
6457 --#Dave Kulik, 10/05/07 regarding Min/MaxInstances:
6458
6459 --The plan has always been to disallow operations directly on the mins and maxes. They would just
6460 --be side-effected by rules like "node.InstanceCount() > x". So if you want to use accumulator
6461 --rules you have a couple of options. You could just write "x AddsTo node.InstanceCount()". Or,
6462 --if you wanted to constrain the domain of InstanceCount without affecting it directly and
6463 --immediately, you could maintain a couple of intermediate variables using accumulator rules and
6464 --constrain InstanceCount relative to those.
6465
6466 --Property ^PROP_NAME is invalid for the node ^NODE_NAME. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
6467
6468 report_and_raise_rule_warning (
6469 p_text => CZ_UTILS.GET_TEXT (
6470 CZ_FCE_W_INVALID_PROPERTY,
6471 'PROP_NAME', CZ_FCE_COMPILE_UTILS.GET_PROPERTY_PATH ( l_property_id ),
6472 'NODE_NAME', CZ_FCE_COMPILE_UTILS.GET_NODE_PATH ( t_exp_psnodeid ( j ),
6473 ps_node_id_table_to_string (
6474 build_complete_path ( t_exp_psnodeid ( j ), t_exp_modelrefexplid( j )))),
6475 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name ),
6476 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH( p_component_id, p_model_path )),
6477 p_warning_location => 'generate_structure_node');
6478
6479 END IF;
6480
6481 IF ( l_property_id = h_templates ('options')) THEN
6482
6483 generate_options ( j, p_input_context, x_output_context );
6484
6485 ELSE
6486
6487 generate_system_property ( l_property_id, t_exp_psnodeid ( j ), t_exp_modelrefexplid ( j ), p_input_context, x_output_context );
6488
6489 END IF;
6490 END IF;
6491 END IF;
6492 END generate_structure_node;
6493 ----------------------------------------------------------------------------------
6494 -- Scope: compile_constraints
6495 PROCEDURE generate_logic_template ( j IN PLS_INTEGER
6496 , p_input_context IN expression_context
6497 , x_output_context IN OUT NOCOPY expression_context
6498 ) IS
6499
6500 l_expr_id VARCHAR2(4000);
6501 l_exprnode_id NUMBER;
6502 l_index PLS_INTEGER;
6503 l_expr_index PLS_INTEGER;
6504
6505 t_lhs_operator type_integer_table;
6506 t_lhs_index type_integer_table;
6507 t_logic_operator type_integer_table;
6508 t_rhs_operator type_integer_table;
6509 t_rhs_index type_integer_table;
6510
6511 l_input_context expression_context;
6512
6513 BEGIN
6514
6515 --This procedure implements generation of simple logic rule. The template application
6516 --specifies the following parameters:
6517
6518 -- param_index = 1: left-hand side AnyTrue or AllTrue operator
6519 -- param_index = 2: left-hand side participant(s)
6520 -- param_index = 3: logic operator
6521 -- param_index = 4: right-hand side AnyTrue or AllTrue operator
6522 -- param_index = 5: right-hand side participant(s)
6523
6524 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
6525
6526 IF ( expr_has_children ( l_expr_id )) THEN
6527
6528 l_index := h_exprid_childrenindex ( l_expr_id ) - 1;
6529
6530 ELSE
6531
6532 report_and_raise_rule_sys_warn (
6533 p_text => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SW_RE_ENODE_CHILDREN,
6534 'EXPR_ID', l_expr_id ),
6535 p_warning_location => 'generate_logic_template');
6536
6537 END IF;
6538
6539 --Parse the template application.
6540
6541 FOR i IN 1..h_exprid_numberofchildren ( l_expr_id ) LOOP
6542
6543 l_expr_index := l_index + i;
6544
6545 CASE t_exp_paramindex ( l_expr_index )
6546
6547 WHEN 1 THEN
6548
6549 t_lhs_operator ( t_lhs_operator.COUNT + 1 ) := l_expr_index;
6550
6551 WHEN 2 THEN
6552
6553 t_lhs_index ( t_lhs_index.COUNT + 1 ) := l_expr_index;
6554
6555 WHEN 3 THEN
6556
6557 t_logic_operator ( t_logic_operator.COUNT + 1 ) := t_exp_templateid ( l_expr_index );
6558
6559 WHEN 4 THEN
6560
6561 t_rhs_operator ( t_rhs_operator.COUNT + 1 ) := l_expr_index;
6562
6563 WHEN 5 THEN
6564
6565 t_rhs_index ( t_rhs_index.COUNT + 1 ) := l_expr_index;
6566
6567 END CASE;
6568 END LOOP;
6569
6570 --Verify the template application.
6571
6572 IF ( t_lhs_operator.COUNT <> 1 OR ( NOT h_operators_3.EXISTS ( t_exp_templateid ( t_lhs_operator ( 1 ))))) THEN
6573 -- 'Left-hand side operator is either not-specified or invalid. Logic rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
6574 report_and_raise_rule_sys_warn(
6575 p_text => GET_NOT_TRANSLATED_TEXT(
6576 CZ_FCE_SW_LR_MISSING_LHS_OP ),
6577 p_warning_location => 'generate_logic_template');
6578
6579 ELSIF ( t_lhs_index.COUNT = 0 ) THEN
6580 -- Right-hand side participants are missing. Logic rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
6581 report_and_raise_rule_warning(
6582 p_text => CZ_UTILS.GET_TEXT(
6583 CZ_FCE_W_LR_MISSING_LHS_PARTS,
6584 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
6585 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
6586 p_warning_location => 'generate_logic_template');
6587
6588 ELSIF ( t_logic_operator.COUNT <> 1 OR ( NOT h_operators_2.EXISTS ( t_logic_operator ( 1 )))) THEN
6589
6590 report_and_raise_rule_sys_warn(
6591 p_text => GET_NOT_TRANSLATED_TEXT(
6592 CZ_FCE_SW_LR_MISSING_LOGIC_OP ),
6593 p_warning_location => 'generate_logic_template');
6594
6595 ELSIF ( t_rhs_operator.COUNT <> 1 OR ( NOT h_operators_3.EXISTS ( t_exp_templateid ( t_rhs_operator ( 1 ))))) THEN
6596
6597 report_and_raise_rule_sys_warn(
6598 p_text => GET_NOT_TRANSLATED_TEXT(
6599 CZ_FCE_SW_LR_MISSING_RHS_OP ),
6600 p_warning_location => 'generate_logic_template');
6601
6602 ELSIF ( t_rhs_index.COUNT = 0 ) THEN
6603 -- Right-hand side participants are missing. Logic rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
6604 report_and_raise_rule_warning(
6605 p_text => CZ_UTILS.GET_TEXT(
6606 CZ_FCE_W_LR_MISSING_RHS_PARTS,
6607 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
6608 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
6609 p_warning_location => 'generate_logic_template');
6610
6611 END IF;
6612
6613 l_input_context.context_type := const_context_logical;
6614
6615 --Need to emulate all participants as children of the AnyTrue or AllTrue operator
6616 --in order to provide context for participants' generation, and to know the exact
6617 --number of arguments to this operator.
6618
6619 l_exprnode_id := t_exp_exprnodeid ( t_lhs_operator ( 1 ));
6620 l_expr_id := TO_CHAR ( l_exprnode_id );
6621
6622 h_exprid_numberofchildren ( l_expr_id ) := 0;
6623
6624 FOR i IN 1..t_lhs_index.COUNT LOOP
6625
6626 t_exp_exprparentid ( t_lhs_index ( i )) := l_exprnode_id;
6627 h_exprid_numberofchildren ( l_expr_id ) := h_exprid_numberofchildren ( l_expr_id ) + 1;
6628
6629 generate_expression ( t_lhs_index ( i ), l_input_context, x_output_context );
6630
6631 END LOOP;
6632
6633 invoke_anyalltrue ( t_exp_templateid ( t_lhs_operator ( 1 )), h_exprid_numberofchildren ( l_expr_id ));
6634
6635 l_exprnode_id := t_exp_exprnodeid ( t_rhs_operator ( 1 ));
6636 l_expr_id := TO_CHAR ( l_exprnode_id );
6637
6638 h_exprid_numberofchildren ( l_expr_id ) := 0;
6639
6640 FOR i IN 1..t_rhs_index.COUNT LOOP
6641
6642 t_exp_exprparentid ( t_rhs_index ( i )) := l_exprnode_id;
6643 h_exprid_numberofchildren ( l_expr_id ) := h_exprid_numberofchildren ( l_expr_id ) + 1;
6644
6645 generate_expression ( t_rhs_index ( i ), l_input_context, x_output_context );
6646
6647 END LOOP;
6648
6649 invoke_anyalltrue ( t_exp_templateid ( t_rhs_operator ( 1 )), h_exprid_numberofchildren ( l_expr_id ));
6650 emit_invokevirtual ( h_operators_2 ( t_logic_operator ( 1 )));
6651
6652 END generate_logic_template;
6653 ----------------------------------------------------------------------------------
6654 -- Scope: compile_constraints
6655 PROCEDURE generate_comparison_template ( j IN PLS_INTEGER
6656 , p_input_context IN expression_context
6657 , x_output_context IN OUT NOCOPY expression_context
6658 ) IS
6659
6660 l_expr_id VARCHAR2(4000);
6661 l_exprnode_id NUMBER;
6662 l_index PLS_INTEGER;
6663 l_expr_index PLS_INTEGER;
6664
6665 t_lhs_operand type_integer_table;
6666 t_comparison_operator type_integer_table;
6667 t_rhs_operand type_integer_table;
6668 t_logic_operator type_integer_table;
6669 t_rhs_operator type_integer_table;
6670 t_rhs_index type_integer_table;
6671
6672 l_input_context expression_context;
6673
6674 BEGIN
6675
6676 --This procedure implements generation of simple comparison rule. The template application
6677 --specifies the following parameters:
6678
6679 -- param_index = 1: left operand of the comparison operator
6680 -- param_index = 2: comparison operator
6681 -- param_index = 3: right operand of the comparison operator
6682 -- param_index = 4: logic operator
6683 -- param_index = 5: right-hand side AnyTrue or AllTrue operator
6684 -- param_index = 6: right-hand side participant(s)
6685
6686 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
6687
6688 IF ( expr_has_children( l_expr_id )) THEN
6689
6690 l_index := h_exprid_childrenindex ( l_expr_id ) - 1;
6691
6692 ELSE
6693
6694 report_and_raise_rule_sys_warn (
6695 p_text => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SW_RE_ENODE_CHILDREN,
6696 'EXPR_ID', l_expr_id ),
6697 p_warning_location => 'generate_comparison_template');
6698
6699 END IF;
6700
6701 --Parse the template application.
6702
6703 FOR i IN 1..h_exprid_numberofchildren ( l_expr_id ) LOOP
6704
6705 l_expr_index := l_index + i;
6706
6707 CASE t_exp_paramindex ( l_expr_index )
6708
6709 WHEN 1 THEN
6710
6711 t_lhs_operand ( t_lhs_operand.COUNT + 1 ) := l_expr_index;
6712
6713 WHEN 2 THEN
6714
6715 t_comparison_operator ( t_comparison_operator.COUNT + 1 ) := t_exp_templateid ( l_expr_index );
6716
6717 WHEN 3 THEN
6718
6719 t_rhs_operand ( t_rhs_operand.COUNT + 1 ) := l_expr_index;
6720
6721 WHEN 4 THEN
6722
6723 t_logic_operator ( t_logic_operator.COUNT + 1 ) := t_exp_templateid ( l_expr_index );
6724
6725 WHEN 5 THEN
6726
6727 t_rhs_operator ( t_rhs_operator.COUNT + 1 ) := l_expr_index;
6728
6729 WHEN 6 THEN
6730
6731 t_rhs_index ( t_rhs_index.COUNT + 1 ) := l_expr_index;
6732
6733 END CASE;
6734 END LOOP;
6735
6736 --Verify the template application.
6737
6738 IF ( t_lhs_operand.COUNT <> 1 ) THEN
6739
6740 report_and_raise_rule_sys_warn(
6741 p_text => GET_NOT_TRANSLATED_TEXT(
6742 CZ_FCE_SW_CR_NO_LHS_OPAND ),
6743 p_warning_location => 'generate_comparison_template');
6744
6745 ELSIF ( t_comparison_operator.COUNT <> 1 OR ( NOT h_operators_2.EXISTS ( t_comparison_operator ( 1 )))) THEN
6746
6747 report_and_raise_rule_sys_warn(
6748 p_text => GET_NOT_TRANSLATED_TEXT(
6749 CZ_FCE_SW_CR_NO_OPERATOR ),
6750 p_warning_location => 'generate_comparison_template');
6751
6752 ELSIF ( t_rhs_operand.COUNT <> 1 ) THEN
6753
6754 report_and_raise_rule_sys_warn(
6755 p_text => GET_NOT_TRANSLATED_TEXT(
6756 CZ_FCE_SW_CR_NO_RHS_OPAND ),
6757 p_warning_location => 'generate_comparison_template');
6758
6759 ELSIF ( t_logic_operator.COUNT <> 1 OR ( NOT h_operators_2.EXISTS ( t_logic_operator ( 1 )))) THEN
6760
6761 report_and_raise_rule_sys_warn(
6762 p_text => GET_NOT_TRANSLATED_TEXT(
6763 CZ_FCE_SW_CR_NO_LOGIC_OP ),
6764 p_warning_location => 'generate_comparison_template');
6765
6766 ELSIF ( t_rhs_operator.COUNT <> 1 OR ( NOT h_operators_3.EXISTS ( t_exp_templateid ( t_rhs_operator ( 1 ))))) THEN
6767
6768 report_and_raise_rule_sys_warn(
6769 p_text => GET_NOT_TRANSLATED_TEXT(
6770 CZ_FCE_SW_CR_NO_RHS_OP ),
6771 p_warning_location => 'generate_comparison_template');
6772
6773 ELSIF ( t_rhs_index.COUNT = 0 ) THEN
6774 -- Right-hand side participants are missing. Comparison rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
6775 report_and_raise_rule_warning(
6776 p_text => CZ_UTILS.GET_TEXT(
6777 CZ_FCE_W_CR_MISSING_RHS_PARTS,
6778 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
6779 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
6780 p_warning_location => 'generate_comparison_template');
6781
6782 END IF;
6783
6784 --Generate the math expression which is left-hand side of the logic operator.
6785
6786 l_input_context.context_type := const_context_numeric;
6787
6788 generate_expression ( t_lhs_operand ( 1 ), l_input_context, x_output_context );
6789 generate_expression ( t_rhs_operand ( 1 ), l_input_context, x_output_context );
6790
6791 invoke_operator2 ( t_comparison_operator ( 1 ), t_rhs_operand ( 1 ), x_output_context );
6792
6793 l_input_context.context_type := const_context_logical;
6794
6795 --Need to emulate all participants as children of the AnyTrue or AllTrue operator
6796 --in order to provide context for participants' generation, and to know the exact
6797 --number of arguments to this operator.
6798
6799 l_exprnode_id := t_exp_exprnodeid ( t_rhs_operator ( 1 ));
6800 l_expr_id := TO_CHAR ( l_exprnode_id );
6801
6802 h_exprid_numberofchildren ( l_expr_id ) := 0;
6803
6804 FOR i IN 1..t_rhs_index.COUNT LOOP
6805
6806 t_exp_exprparentid ( t_rhs_index ( i )) := l_exprnode_id;
6807 h_exprid_numberofchildren ( l_expr_id ) := h_exprid_numberofchildren ( l_expr_id ) + 1;
6808
6809 generate_expression ( t_rhs_index ( i ), l_input_context, x_output_context );
6810
6811 END LOOP;
6812
6813 invoke_anyalltrue ( t_exp_templateid ( t_rhs_operator ( 1 )), h_exprid_numberofchildren ( l_expr_id ));
6814 emit_invokevirtual ( h_operators_2 ( t_logic_operator ( 1 )));
6815
6816 END generate_comparison_template;
6817 ----------------------------------------------------------------------------------
6818 FUNCTION next_interval_key ( p_target_id IN PLS_INTEGER ) RETURN VARCHAR2 IS
6819
6820 l_seq PLS_INTEGER := t_acc_target_sequence ( p_target_id );
6821
6822 BEGIN
6823
6824 t_acc_target_sequence ( p_target_id ) := l_seq + 1;
6825 RETURN TO_CHAR ( l_seq ) || '$' || t_acc_targets ( p_target_id );
6826
6827 END next_interval_key;
6828 ----------------------------------------------------------------------------------
6829 --This function adds instance quantifies, generated for the new contribution, to the
6830 --list of instance quantifiers of the record with index p_index.
6831
6832 PROCEDURE combine_instance_quantifiers ( p_target_id IN PLS_INTEGER, p_index IN PLS_INTEGER ) IS
6833
6834 l_count PLS_INTEGER;
6835
6836 BEGIN
6837
6838 --Add all the quantifiers that were created for this contribution and are not present in the
6839 --record's arrays, to the record.
6840
6841 FOR i IN 1..t_acc_local_quantifiers.COUNT LOOP
6842
6843 IF ( NOT t_acc_contributors ( p_target_id )( p_index ).hash_quantifiers.EXISTS ( t_acc_local_quantifiers ( i ))) THEN
6844
6845 l_count := t_acc_contributors ( p_target_id )( p_index ).quantifiers.COUNT + 1;
6846
6847 t_acc_contributors ( p_target_id )( p_index ).quantifiers ( l_count ) := t_acc_local_quantifiers ( i );
6848 t_acc_contributors ( p_target_id )( p_index ).hash_quantifiers ( t_acc_local_quantifiers ( i )) := 1;
6849
6850 END IF;
6851 END LOOP;
6852 END combine_instance_quantifiers;
6853 ----------------------------------------------------------------------------------
6854 --This function is used to store a combined contribution for the newly created record
6855 --with index p_index. When this function is called, the new contribution is on top of
6856 --stack.
6857
6858 --The function combines the new contribution with the contribution which is currently
6859 --stored in the register p_exist_key (if any) and stores the combined contribution in
6860 --the register of the new record (the value is removed from stack). Target's instance
6861 --quantifiers are combined.
6862
6863 PROCEDURE combine_contributions ( p_target_id IN PLS_INTEGER, p_index IN PLS_INTEGER, p_exist_key IN VARCHAR2 ) IS
6864 BEGIN
6865
6866 aload_register ('value');
6867
6868 IF ( p_exist_key IS NOT NULL ) THEN
6869
6870 aload_register ( p_exist_key );
6871 emit_invokevirtual ('INumExprDef.sum(INumExprDef)');
6872
6873 END IF;
6874
6875 IF ( t_acc_contributors ( p_target_id )( p_index ).interval_key IS NULL ) THEN
6876
6877 t_acc_contributors ( p_target_id )( p_index ).interval_key := next_interval_key ( p_target_id );
6878
6879 END IF;
6880
6881 astore_register ( t_acc_contributors ( p_target_id )( p_index ).interval_key );
6882 combine_instance_quantifiers ( p_target_id, p_index );
6883
6884 END combine_contributions;
6885 ----------------------------------------------------------------------------------
6886 PROCEDURE combine_contribution_records ( p_target_id IN PLS_INTEGER, p_index IN PLS_INTEGER, p_exist_key IN VARCHAR2 ) IS
6887
6888 l_count PLS_INTEGER;
6889
6890 l_exist_mask_ RAW(16);
6891 l_new_mask_ RAW(16);
6892
6893 l_common_mask VARCHAR2(16);
6894 l_exist_mask VARCHAR2(16);
6895 l_new_mask VARCHAR2(16);
6896
6897 BEGIN
6898
6899 l_exist_mask_ := HEXTORAW ( t_acc_contributors ( p_target_id )( p_index ).effective_usage_mask );
6900 l_new_mask_ := HEXTORAW ( this_effective_usages );
6901
6902 l_common_mask := RAWTOHEX ( UTL_RAW.BIT_OR ( l_exist_mask_, l_new_mask_ ));
6903
6904 IF ( l_common_mask <> const_mask_no_usages ) THEN
6905
6906 --Usages, defined only for the existing contribution record.
6907
6908 l_exist_mask := RAWTOHEX ( UTL_RAW.BIT_OR ( l_exist_mask_, UTL_RAW.BIT_COMPLEMENT ( l_new_mask_ )));
6909
6910 --Usages, defined only for the new contribution.
6911
6912 l_new_mask := RAWTOHEX ( UTL_RAW.BIT_OR ( UTL_RAW.BIT_COMPLEMENT ( l_exist_mask_ ), l_new_mask_ ));
6913
6914 IF ( l_common_mask = t_acc_contributors ( p_target_id )( p_index ).effective_usage_mask ) THEN
6915
6916 --New usage mask containt the existing or masks are equal, combine contributions on the existing
6917 --record.
6918
6919 IF ( t_acc_contributors ( p_target_id )( p_index ).interval_key IS NOT NULL ) THEN
6920
6921 --If the interval has a contribution stored in a register, we need to create a new register
6922 --because we will be changing the contribution while the existing register may be also used
6923 --on some other interval.
6924
6925 t_acc_contributors ( p_target_id )( p_index ).interval_key := next_interval_key ( p_target_id );
6926
6927 END IF;
6928
6929 combine_contributions ( p_target_id, p_index, p_exist_key );
6930
6931 ELSE
6932
6933 --Existing usage mask contains the new or masks intersect. We need to change the mask
6934 --on the existing record to l_exist_mask because only on this usages we will have the
6935 --existing contribution. Then we create a new record for common usages summing up the
6936 --contributions.
6937
6938 l_count := t_acc_contributors ( p_target_id ).COUNT + 1;
6939 t_acc_contributors ( p_target_id )( l_count ) := t_acc_contributors ( p_target_id )( p_index );
6940
6941 t_acc_contributors ( p_target_id )( p_index ).effective_usage_mask := l_exist_mask;
6942
6943 t_acc_contributors ( p_target_id )( l_count ).effective_usage_mask := l_common_mask;
6944 t_acc_contributors ( p_target_id )( l_count ).interval_key := next_interval_key ( p_target_id );
6945
6946 combine_contributions ( p_target_id, l_count, p_exist_key );
6947
6948 END IF;
6949 END IF;
6950 END combine_contribution_records;
6951 ----------------------------------------------------------------------------------
6952 PROCEDURE combine_contributors ( p_target_id IN PLS_INTEGER ) IS
6953
6954 l_contribs PLS_INTEGER;
6955 l_count PLS_INTEGER;
6956
6957 l_eff_from DATE;
6958 l_eff_until DATE;
6959
6960 BEGIN
6961
6962 IF ( t_acc_contributors.EXISTS ( p_target_id )) THEN
6963
6964 --There are existing contributions to this target. We need combine this new contribution
6965 --with others according to effectivities and usages.
6966
6967 --The new contribution is currently on top of the stack and needs to be available for
6968 --each interval that we process. We store it in a dedicated register and then push it
6969 --from there before each use.
6970
6971 astore_register ('value');
6972 l_contribs := t_acc_contributors ( p_target_id ).COUNT;
6973
6974 FOR i IN 1..l_contribs LOOP
6975
6976 l_eff_from := t_acc_contributors ( p_target_id )( i ).effective_from;
6977 l_eff_until := t_acc_contributors ( p_target_id )( i ).effective_until;
6978
6979 IF ( this_effective_until > l_eff_from AND this_effective_from < l_eff_until ) THEN
6980
6981 --Effectivity intervals intersect.
6982
6983 IF ( this_effective_from <= l_eff_from AND this_effective_until >= l_eff_until ) THEN
6984
6985 -- |------------------------| - existing interval
6986 -- |------------------------------------| - new interval
6987
6988 --The new contribution's effectivity interval contains the existing interval, or intervals
6989 --are the same, including the case when both are always effective.
6990
6991 combine_contribution_records ( p_target_id, i, t_acc_contributors ( p_target_id )( i ).interval_key );
6992
6993 ELSE
6994
6995 --One or both ends of the new effectivity interval are inside the existing interval, split them
6996 --into several intervals and add them to the table of contribution records.
6997
6998 l_count := t_acc_contributors ( p_target_id ).COUNT + 1;
6999 t_acc_contributors ( p_target_id )( l_count ) := t_acc_contributors ( p_target_id )( i );
7000
7001 IF ( this_effective_from <= l_eff_from ) THEN
7002
7003 -- |------------------------| - existing interval
7004 -- |----------------| - new interval
7005
7006 --Modify the existing interval. As contributions does not change, we don't need to store it
7007 --in the register, it's already there.
7008
7009 t_acc_contributors ( p_target_id )( i ).effective_from := this_effective_until;
7010
7011 --Create a new record for the intersection.
7012
7013 t_acc_contributors ( p_target_id )( l_count ).effective_from := l_eff_from;
7014 t_acc_contributors ( p_target_id )( l_count ).effective_until := this_effective_until;
7015
7016 ELSIF ( this_effective_until >= l_eff_until ) THEN
7017
7018 -- |------------------------| - existing interval
7019 -- |-----------------| - new interval
7020
7021 --Modify the existing interval. As contributions does not change, we don't need to store it
7022 --in the register, it's already there.
7023
7024 t_acc_contributors ( p_target_id )( i ).effective_until := this_effective_from;
7025
7026 --Create a new record for the intersection.
7027
7028 t_acc_contributors ( p_target_id )( l_count ).effective_from := this_effective_from;
7029 t_acc_contributors ( p_target_id )( l_count ).effective_until := l_eff_until;
7030
7031 ELSE
7032
7033 -- |------------------------| - existing interval
7034 -- |------------| - new interval
7035
7036 --Split the existing interval into two with the same contributions.
7037
7038 t_acc_contributors ( p_target_id )( i ).effective_until := this_effective_from;
7039 t_acc_contributors ( p_target_id )( l_count ).effective_from := this_effective_until;
7040
7041 --Create a new record for the intersection.
7042
7043 l_count := l_count + 1;
7044 t_acc_contributors ( p_target_id )( l_count ) := t_acc_contributors ( p_target_id )( i );
7045
7046 t_acc_contributors ( p_target_id )( l_count ).effective_from := this_effective_from;
7047 t_acc_contributors ( p_target_id )( l_count ).effective_until := this_effective_until;
7048
7049 END IF;
7050
7051 --Process the intersection for usages.
7052
7053 combine_contribution_records ( p_target_id, l_count, t_acc_contributors ( p_target_id )( i ).interval_key );
7054
7055 END IF;
7056 END IF;
7057 END LOOP;
7058
7059 ELSE
7060
7061 --This is the first contributor to this target.
7062
7063 l_count := 1;
7064
7065 IF ( this_effective_from > const_epoch_begin ) THEN
7066
7067 t_acc_contributors ( p_target_id )( l_count ).effective_from := const_epoch_begin;
7068 t_acc_contributors ( p_target_id )( l_count ).effective_until := this_effective_from;
7069 t_acc_contributors ( p_target_id )( l_count ).effective_usage_mask := const_mask_all_usages;
7070
7071 t_acc_contributors ( p_target_id )( l_count ).interval_key := NULL;
7072 t_acc_contributors ( p_target_id )( l_count ).quantifiers := t_acc_quantifiers ( p_target_id );
7073 t_acc_contributors ( p_target_id )( l_count ).hash_quantifiers := h_acc_quantifiers ( p_target_id );
7074
7075 l_count := l_count + 1;
7076
7077 END IF;
7078
7079 t_acc_contributors ( p_target_id )( l_count ).interval_key := next_interval_key ( p_target_id );
7080
7081 --Note that t_acc_quantifiers at this point contains also the target's quantifier, so
7082 --we are initializing the quantifiers array with all quantifiers generated for the
7083 --first contribution to this target. After that we will be appending this array, when
7084 --combining contributions, with quantifiers, generated for contributors.
7085
7086 t_acc_contributors ( p_target_id )( l_count ).effective_from := this_effective_from;
7087 t_acc_contributors ( p_target_id )( l_count ).effective_until := this_effective_until;
7088 t_acc_contributors ( p_target_id )( l_count ).effective_usage_mask := this_effective_usages;
7089
7090 t_acc_contributors ( p_target_id )( l_count ).quantifiers := t_acc_quantifiers ( p_target_id );
7091 t_acc_contributors ( p_target_id )( l_count ).hash_quantifiers := h_acc_quantifiers ( p_target_id );
7092
7093 astore_register ( t_acc_contributors ( p_target_id )( l_count ).interval_key );
7094
7095 IF ( this_effective_usages <> const_mask_all_usages ) THEN
7096
7097 --If this contribution is not for all usages, we need to add a dummy record with null
7098 --key and complemental usage mask. It works for the same purpose as dummy effectivity
7099 --intervals.
7100
7101 l_count := l_count + 1;
7102
7103 t_acc_contributors ( p_target_id )( l_count ).effective_from := this_effective_from;
7104 t_acc_contributors ( p_target_id )( l_count ).effective_until := this_effective_until;
7105 t_acc_contributors ( p_target_id )( l_count ).effective_usage_mask := RAWTOHEX ( UTL_RAW.BIT_COMPLEMENT ( this_effective_usages ));
7106
7107 t_acc_contributors ( p_target_id )( l_count ).interval_key := NULL;
7108 t_acc_contributors ( p_target_id )( l_count ).quantifiers := t_acc_quantifiers ( p_target_id );
7109 t_acc_contributors ( p_target_id )( l_count ).hash_quantifiers := h_acc_quantifiers ( p_target_id );
7110
7111 END IF;
7112
7113 IF ( this_effective_until < const_epoch_end ) THEN
7114
7115 l_count := l_count + 1;
7116
7117 t_acc_contributors ( p_target_id )( l_count ).effective_from := this_effective_until;
7118 t_acc_contributors ( p_target_id )( l_count ).effective_until := const_epoch_end;
7119 t_acc_contributors ( p_target_id )( l_count ).effective_usage_mask := const_mask_all_usages;
7120
7121 t_acc_contributors ( p_target_id )( l_count ).interval_key := NULL;
7122 t_acc_contributors ( p_target_id )( l_count ).quantifiers := t_acc_quantifiers ( p_target_id );
7123 t_acc_contributors ( p_target_id )( l_count ).hash_quantifiers := h_acc_quantifiers ( p_target_id );
7124
7125 END IF;
7126 END IF;
7127 END combine_contributors;
7128 ----------------------------------------------------------------------------------
7129 -- Scope: compile_constraints
7130 PROCEDURE generate_accumulator_template ( j IN PLS_INTEGER
7131 , p_input_context IN expression_context
7132 , x_output_context IN OUT NOCOPY expression_context
7133 ) IS
7134
7135 l_expr_id VARCHAR2(4000);
7136 l_index PLS_INTEGER;
7137 l_expr_index PLS_INTEGER;
7138 l_count PLS_INTEGER;
7139 l_key VARCHAR2(4000);
7140
7141 t_contributor_index type_integer_table;
7142 t_multiplier type_number_table;
7143 t_accumulation_op type_integer_table;
7144 t_rounding_op type_integer_table;
7145 t_target_index type_integer_table;
7146
7147 l_input_context expression_context;
7148
7149 BEGIN
7150
7151 --This procedure implements generation of simple accumulation rule. The template application
7152 --specifies the following parameters:
7153
7154 -- param_index = 1: contributor(s)
7155 -- param_index = 2: multiplier (constant)
7156 -- param_index = 3: accumulation operator
7157 -- param_index = 4: rounding operator
7158 -- param_index = 5: target
7159
7160 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
7161
7162 IF ( expr_has_children ( l_expr_id )) THEN
7163
7164 l_index := h_exprid_childrenindex ( l_expr_id ) - 1;
7165
7166 ELSE
7167
7168 report_and_raise_rule_sys_warn (
7169 p_text => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SW_RE_ENODE_CHILDREN,
7170 'EXPR_ID', l_expr_id ),
7171 p_warning_location => 'generate_accumulator_template');
7172
7173 END IF;
7174
7175 --Parse the template application.
7176
7177 FOR i IN 1..h_exprid_numberofchildren ( l_expr_id ) LOOP
7178
7179 l_expr_index := l_index + i;
7180
7181 CASE t_exp_paramindex ( l_expr_index )
7182
7183 WHEN 1 THEN
7184
7185 t_contributor_index ( t_contributor_index.COUNT + 1 ) := l_expr_index;
7186
7187 WHEN 2 THEN
7188
7189 t_multiplier ( t_multiplier.COUNT + 1 ) := NVL ( t_exp_datanumvalue ( l_expr_index ), 1 );
7190
7191 WHEN 3 THEN
7192
7193 t_accumulation_op ( t_accumulation_op.COUNT + 1 ) := t_exp_templateid ( l_expr_index );
7194
7195 WHEN 4 THEN
7196
7197 t_rounding_op ( t_rounding_op.COUNT + 1 ) := t_exp_templateid ( l_expr_index );
7198
7199 WHEN 5 THEN
7200
7201 t_target_index ( t_target_index.COUNT + 1 ) := l_expr_index;
7202
7203 END CASE;
7204 END LOOP;
7205
7206 --Verify the template application.
7207
7208 IF ( t_contributor_index.COUNT = 0 ) THEN
7209
7210 report_and_raise_rule_sys_warn(
7211 p_text => GET_NOT_TRANSLATED_TEXT(
7212 CZ_FCE_SW_AR_NO_LHS_OPAND ),
7213 p_warning_location => 'generate_accumulator_template');
7214
7215 ELSIF ( t_multiplier.COUNT <> 1 ) THEN
7216
7217 report_and_raise_rule_sys_warn(
7218 p_text => GET_NOT_TRANSLATED_TEXT(
7219 CZ_FCE_SW_AR_NO_MLTIPLIER ),
7220 p_warning_location => 'generate_accumulator_template');
7221
7222 ELSIF ( t_accumulation_op.COUNT <> 1 OR ( NOT h_accumulation_ops.EXISTS ( t_accumulation_op ( 1 )))) THEN
7223
7224 report_and_raise_rule_sys_warn(
7225 p_text => GET_NOT_TRANSLATED_TEXT(
7226 CZ_FCE_SW_AR_NO_OPERATOR ),
7227 p_warning_location => 'generate_accumulator_template');
7228
7229 ELSIF ( t_rounding_op.COUNT <> 1 OR ( NOT h_rounding_ops.EXISTS ( t_rounding_op ( 1 )))) THEN
7230
7231 report_and_raise_rule_sys_warn(
7232 p_text => GET_NOT_TRANSLATED_TEXT(
7233 CZ_FCE_SW_AR_NO_ROUND_OP ),
7234 p_warning_location => 'generate_accumulator_template');
7235
7236 ELSIF ( t_target_index.COUNT <> 1 ) THEN
7237
7238 report_and_raise_rule_sys_warn(
7239 p_text => GET_NOT_TRANSLATED_TEXT(
7240 CZ_FCE_SW_AR_NO_RHS_OPAND ),
7241 p_warning_location => 'generate_accumulator_template');
7242
7243 END IF;
7244
7245 --Need to generate the target first, because generation of contributor will depend on the
7246 --target (LCA). Cannot just generate the path here because target can be an argument, for
7247 --example, in case of FORALL operator.
7248
7249 l_input_context.context_type := const_context_target;
7250 generate_expression ( t_target_index ( 1 ), l_input_context, x_output_context );
7251
7252 l_count := x_output_context.context_num_data;
7253 l_key := x_output_context.context_data;
7254
7255 --If output context is 'target', the target didn't exist and needs to be stored.
7256 --For an exiting target, the context would have been changed to 'generic' in
7257 --generate_path procedure.
7258
7259 IF ( x_output_context.context_type = const_context_target ) THEN
7260
7261 astore_register ( l_key );
7262
7263 t_target_quantifiers ( l_count ) := t_acc_quantifiers ( l_count );
7264 h_target_quantifiers ( l_count ) := h_acc_quantifiers ( l_count );
7265
7266 END IF;
7267
7268 --If there are more than 2 contributors, we will put them into an array and call
7269 --IModelDef.sum. To do this, we need extra model def on stack.
7270
7271 IF ( t_contributor_index.COUNT > 2 ) THEN
7272
7273 aload_model_def ( p_component_id );
7274
7275 END IF;
7276
7277 --Now generate all the contributors.
7278
7279 t_acc_local_quantifiers.DELETE;
7280
7281 FOR i IN 1..t_contributor_index.COUNT LOOP
7282
7283 l_input_context.context_type := const_context_contributor;
7284 l_input_context.context_num_data := l_count;
7285
7286 generate_expression ( t_contributor_index ( i ), l_input_context, x_output_context );
7287
7288 --Multiply by the multiplier if it is other than 1.
7289
7290 IF ( t_multiplier ( 1 ) <> 1 ) THEN
7291
7292 emit_invokevirtual ( CASE push_numeric_literal ( t_multiplier ( 1 ))
7293 WHEN h_datatypes ('integer') THEN 'INumExprDef.prod(int)'
7294 ELSE 'INumExprDef.prod(double)'
7295 END );
7296 END IF;
7297
7298 --Apply the rounding operator if any.
7299
7300 IF ( t_rounding_op ( 1 ) <> h_templates ('none')) THEN
7301
7302 emit_invokevirtual ( h_operators_1 ( t_rounding_op ( 1 )));
7303
7304 END IF;
7305 END LOOP;
7306
7307 --Sum up all the generated contributors as appropriate.
7308
7309 IF ( t_contributor_index.COUNT = 2 ) THEN
7310
7311 emit_invokevirtual ('INumExprDef.sum(INumExprDef)');
7312
7313 ELSIF ( t_contributor_index.COUNT > 2 ) THEN
7314
7315 create_array ( t_contributor_index.COUNT, h_javatypes ('INumExprDef'));
7316 populate_array ( t_contributor_index.COUNT );
7317 emit_invokevirtual ('IModelDef.sum(INumExprDef[])');
7318
7319 END IF;
7320
7321 IF ( t_accumulation_op ( 1 ) = h_templates ('subtractsfrom')) THEN
7322
7323 emit_invokevirtual ('INumExprDef.neg()');
7324
7325 END IF;
7326
7327 combine_contributors ( l_count );
7328 x_output_context.context_type := const_context_accumulation;
7329
7330 END generate_accumulator_template;
7331 ----------------------------------------------------------------------------------
7332 -- Scope: compile_constraints
7333 PROCEDURE generate_compat_table ( p_compat_table type_compat_table
7334 , p_input_context IN expression_context
7335 , x_output_context IN OUT NOCOPY expression_context
7336 ) IS
7337
7338 l_key VARCHAR2(4000);
7339 l_exclude_key VARCHAR2(4000);
7340 l_node_id VARCHAR2(4000);
7341 l_expl_id VARCHAR2(4000);
7342 l_option_id NUMBER;
7343
7344 l_participants PLS_INTEGER;
7345 l_combinations PLS_INTEGER;
7346 l_return PLS_INTEGER;
7347 l_index PLS_INTEGER;
7348 l_count PLS_INTEGER;
7349
7350 tl_sizes type_integer_table;
7351 tl_excludes_id type_number_table;
7352 tl_excludes type_varchar4000_table;
7353 hl_options type_datahashtable_table;
7354
7355 BEGIN
7356
7357 h_instancequantifiers.DELETE;
7358 t_instancequantifiers.DELETE;
7359
7360 l_combinations := p_compat_table.combinations.COUNT;
7361 l_participants := p_compat_table.participants.COUNT;
7362
7363 --This is to call IModelDef.addConstraint
7364
7365 aload_model_def ( p_component_id );
7366
7367 --This is to call IModelDef.compat. As model def is definitely in a local variable after
7368 --the previous call, this may be faster than dup.
7369
7370 IF ( l_combinations > 0 ) THEN
7371
7372 --We will need to call compat only if there are combinations.
7373
7374 aload_model_def ( p_component_id );
7375
7376 END IF;
7377
7378 --Generate all the participants.
7379
7380 FOR i IN 1..l_participants LOOP
7381
7382 IF ( h_psnid_detailedtype ( p_compat_table.participants ( i ).ps_node_id ) NOT IN
7383 ( h_psntypes ('optionfeature'), h_psntypes ('bomoptionclass'))) THEN
7384 -- Invalid participant in compatibility rule. Valid participants are Option Feature or BOM Option Class nodes. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
7385 report_and_raise_rule_warning(
7386 p_text => CZ_UTILS.GET_TEXT(
7387 CZ_FCE_W_CMR_INVALID_PART,
7388 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
7389 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
7390 p_warning_location => 'generate_compat_table');
7391
7392 END IF;
7393
7394 l_return := generate_path ( p_compat_table.participants ( i ).ps_node_id
7395 , p_compat_table.participants ( i ).model_ref_expl_id
7396 , p_input_context
7397 , x_output_context );
7398
7399 IF ( l_return = const_quantifier_created ) THEN
7400
7401 emit_invokevirtual('IInstanceQuantifier.getExprFromInstance(IExprDef)');
7402
7403 END IF;
7404
7405 --We will not need to store in a local variable if there is no excludes for this feature,
7406 --or if there are no combinations, so this can be optimized.
7407
7408 l_key := TO_CHAR ( p_compat_table.participants ( i ).ps_node_id ) || '-' ||
7409 TO_CHAR ( p_compat_table.participants ( i ).model_ref_expl_id );
7410
7411 IF ( l_combinations > 0 ) THEN
7412
7413 IF ( NOT local_variable_defined ( l_key )) THEN
7414
7415 copyto_local_variable ( l_key );
7416
7417 END IF;
7418
7419 ELSE
7420
7421 --If there is no combinations, we will be generating an exclude, and do not need to
7422 --store the participants, instead, we need to apply the logical context.
7423
7424 apply_context ( p_compat_table.participants ( i ).ps_node_id, l_return, const_context_logical );
7425
7426 END IF;
7427 END LOOP;
7428
7429 IF ( l_combinations = 0 ) THEN
7430
7431 --There is no combinations. This is possible between a primary and an optional feature.
7432 --Generate exclude and return.
7433
7434 --#<optimization>As an optimization, we could collect all optional features with no selections
7435 --before we go into generate_compat_table. There is no need to build compatibility tables for
7436 --such features and process them separately, we could just exclude all of them. This could be
7437 --implemented, but it's not a good idea to use Design Chart for such purposes anyway.
7438
7439 emit_invokevirtual ('ILogicExprDef.excludes(ILogicExprDef)');
7440 set_reason_id ();
7441 add_constraint ();
7442
7443 RETURN;
7444 END IF;
7445
7446 --Create the array of participants that will be the first argument to compat.
7447
7448 create_array ( l_participants, h_javatypes ('Object'));
7449 populate_array ( l_participants );
7450
7451 --Now we need to create the second argument for the compat - a two-dimensional array of all combinations.
7452 --For non-bom, the second dimension is the array of the names of options comprising the combination. For
7453 --bom the type depends on the bom type. Mixed case is also possible.
7454
7455 --Create an array for each combination. Note, that the correct order of options within the combinations
7456 --is guaranteed by the construction of p_compat_table.combinations
7457
7458 FOR i IN 1..l_combinations LOOP
7459 FOR j IN 1..l_participants LOOP
7460
7461 l_key := TO_CHAR ( p_compat_table.participants ( j ).ps_node_id ) || '-' ||
7462 TO_CHAR ( p_compat_table.participants ( j ).model_ref_expl_id );
7463
7464 l_option_id := p_compat_table.combinations ( i )( j ).ps_node_id;
7465 l_index := h_psnid_backindex ( l_option_id );
7466
7467 IF ( t_psn_psnodetype ( l_index ) = h_psntypes ('option')) THEN
7468
7469 push_variable_name ( l_option_id );
7470
7471 ELSE
7472
7473 --The parent is bom. The following approach should work for all kinds of options
7474 --including references.
7475
7476 IF ( h_psnid_devlprojectid ( l_option_id ) = p_component_id ) THEN
7477
7478 haload_object ( l_option_id , 1 );
7479
7480 ELSE
7481
7482 --push_variable assumes that the parent is on the stack if the variable is remote.
7483 --Note that we need the participant in the local context and we won't be calling
7484 --getVarRef on it therefore we don't neef to dup the parent as push_variable does.
7485
7486 aload_context_node ( l_key, const_context_generic );
7487
7488 emit_invokevirtual ( 'ISingletonExprDef.getType()');
7489 push_variable_name ( l_option_id );
7490 emit_invokevirtual ( 'IModelDef.getVar(String)');
7491
7492 END IF;
7493 END IF;
7494
7495 --Mark that this option participates in a combination.
7496
7497 hl_options ( j )( TO_CHAR ( l_option_id )) := 1;
7498
7499 END LOOP;
7500
7501 create_array ( l_participants, h_javatypes ('Object'));
7502 populate_array ( l_participants );
7503
7504 END LOOP;
7505
7506 --Create two-dimensional array and populate the first dimension.
7507
7508 tl_sizes ( 1 ) := l_combinations;
7509 tl_sizes ( 2 ) := l_participants;
7510
7511 create_multi_array ( tl_sizes, h_javatypes ('Object'));
7512 populate_array ( l_combinations );
7513
7514 --Finally call the compat to generate the constraint.
7515
7516 emit_invokevirtual ('IModelDef.compat(Object[], Object[][])');
7517
7518 set_reason_id ();
7519 add_constraint ();
7520
7521 --Now we need to generate all the exclude constraints for the options that don't
7522 --participate in compat.
7523
7524 FOR i IN 1..l_participants LOOP
7525
7526 --Collect all the options that are not in the combinations.
7527
7528 l_node_id := TO_CHAR ( p_compat_table.participants ( i ).ps_node_id );
7529 l_expl_id := TO_CHAR ( p_compat_table.participants ( i ).model_ref_expl_id );
7530
7531 l_key := l_node_id || '-' || l_expl_id;
7532
7533 l_index := h_psnid_backindex ( l_node_id );
7534
7535 IF ( h_psnid_numberofchildren ( l_node_id ) <> hl_options ( i ).COUNT ) THEN
7536
7537 --Number of children is different from the number of options that participate
7538 --in combinations, need to generate exclude. Note that this condition work in
7539 --all cases, bom and non-bom, as non-bom children of a bom are considered as
7540 --participating options - Developer allows to select them for combinations.
7541
7542 --We will be adding another contraint which may have it's own ForAll.
7543
7544 h_instancequantifiers.DELETE;
7545 t_instancequantifiers.DELETE;
7546
7547 --Also, we need one more model def to call addConstraint.
7548
7549 aload_model_def ( p_component_id );
7550
7551 --All children directly follow the participant in the structure.
7552
7553 l_index := l_index + 1;
7554 l_count := 0;
7555
7556 --The participant cannot be a bom reference, so we don't have to use is_bom.
7557
7558 IF ( NOT is_bom_node ( l_index )) THEN
7559
7560 --This is a feature.
7561 --Put the participant on stack for whatever method we are going to call.
7562
7563 aload_context_node ( l_key, const_context_generic );
7564
7565 WHILE ( l_index <= h_psnid_lastchildindex ( l_node_id )) LOOP
7566
7567 IF ( NOT hl_options ( i ).EXISTS ( TO_CHAR ( t_psn_psnodeid ( l_index )))) THEN
7568
7569 --Push option name as a parameter to intersect.
7570
7571 push_variable_name ( t_psn_psnodeid ( l_index ));
7572 l_count := l_count + 1;
7573
7574 END IF;
7575
7576 l_index := l_index + 1;
7577
7578 END LOOP;
7579
7580 IF ( l_count = 1 ) THEN
7581
7582 --Just one option, generate contains instead of intersects.
7583
7584 emit_invokevirtual ('ISetExprDef.contains(Object)');
7585
7586 ELSE
7587
7588 create_array ( l_count, h_javatypes ('Object'));
7589 populate_array ( l_count );
7590 emit_invokevirtual ('ISetExprDef.intersects(Object[])');
7591
7592 END IF;
7593
7594 ELSE
7595
7596 tl_excludes_id.DELETE;
7597
7598 --The participant is a bom. All children still directly follow the participant in
7599 --the structure, but there can also be tokens, so we need to check the parent_id.
7600
7601 WHILE ( l_index <= h_psnid_lastchildindex ( l_node_id ) AND t_psn_parentid ( l_index ) = l_node_id ) LOOP
7602
7603 l_option_id := t_psn_psnodeid ( l_index );
7604
7605 IF ( NOT hl_options ( i ).EXISTS ( TO_CHAR ( l_option_id ))) THEN
7606
7607 l_count := l_count + 1;
7608 tl_excludes_id ( l_count ) := l_option_id ;
7609
7610 END IF;
7611
7612 l_index := l_index + 1;
7613
7614 END LOOP;
7615
7616 IF ( l_count > 2 ) THEN
7617
7618 --Need this to call AnyTrue.
7619
7620 aload_model_def ( p_component_id );
7621
7622 END IF;
7623
7624 FOR i IN 1..l_count LOOP
7625
7626 l_option_id := tl_excludes_id ( i );
7627
7628 aload_context_node ( l_key, const_context_generic );
7629 push_variable ( l_option_id, 'ISingletonExprDef');
7630 emit_invokevirtual ('ISingletonExprDef.getVarRef(IExprDef)');
7631
7632 apply_logical_context ( l_option_id, p_input_context.context_type );
7633
7634 END LOOP;
7635
7636 --If there's only one excluding option, do nothing. If there's two, call or, otherwise
7637 --create an array an call AnyTrue.
7638
7639 IF ( l_count = 2 ) THEN
7640
7641 emit_invokevirtual ('ILogicExprDef.or(ILogicExprDef)');
7642
7643 ELSIF ( l_count > 2) THEN
7644
7645 create_array ( l_count, h_javatypes ('ILogicExprDef'));
7646 populate_array ( l_count );
7647 emit_invokevirtual ('IModelDef.any(ILogicExprDef[])');
7648
7649 END IF;
7650 END IF;
7651
7652 tl_excludes.DELETE;
7653 l_index := 1;
7654
7655 FOR j IN 1..l_participants LOOP
7656
7657 l_exclude_key := TO_CHAR ( p_compat_table.participants ( j ).ps_node_id ) || '-' ||
7658 TO_CHAR ( p_compat_table.participants ( j ).model_ref_expl_id );
7659
7660 IF ( l_exclude_key <> l_key ) THEN
7661
7662 tl_excludes ( l_index ) := l_exclude_key;
7663 l_index := l_index + 1;
7664
7665 END IF;
7666 END LOOP;
7667
7668 IF ( tl_excludes.COUNT > 2) THEN
7669
7670 --We need this to call AllTrue.
7671
7672 aload_model_def ( p_component_id );
7673
7674 END IF;
7675
7676 --Push all the participants to exclude on the stack.
7677
7678 FOR j IN 1..tl_excludes.COUNT LOOP
7679
7680 aload_context_node ( tl_excludes ( j ), const_context_logical );
7681
7682 END LOOP;
7683
7684 --If there is only one participant for exclude, do nothing. If there's two, use 'and',
7685 --otherwise create an array and call AllTrue.
7686
7687 IF ( tl_excludes.COUNT = 2 ) THEN
7688
7689 emit_invokevirtual ('ILogicExprDef.and(ILogicExprDef)');
7690
7691 ELSIF ( tl_excludes.COUNT > 2 ) THEN
7692
7693 create_array ( tl_excludes.COUNT, h_javatypes ('ILogicExprDef'));
7694 populate_array ( tl_excludes.COUNT );
7695 emit_invokevirtual ('IModelDef.all(ILogicExprDef[])');
7696
7697 END IF;
7698
7699 --Now call the exclude and add the constraint.
7700
7701 emit_invokevirtual ('ILogicExprDef.excludes(ILogicExprDef)');
7702 set_reason_id ();
7703 add_constraint ();
7704
7705 END IF; --exclude required.
7706 END LOOP;
7707 END generate_compat_table;
7708 ----------------------------------------------------------------------------------
7709 --If p_emptiness is true, the table is allowed to be empty - no combinations. This
7710 --is true for the primary-optional compat tables.
7711 -- Scope: compile_constraints
7712 PROCEDURE verify_compatibility_table ( p_compat_table IN type_compat_table, p_emptiness IN BOOLEAN ) IS
7713
7714 l_count PLS_INTEGER;
7715 l_maximum PLS_INTEGER;
7716 l_index PLS_INTEGER;
7717
7718 hl_parentid type_data_hashtable;
7719
7720 BEGIN
7721
7722 IF ( p_compat_table.participants.COUNT < 2 ) THEN
7723
7724 --#<verification>
7725 --This error can actually be raised here only for explicit compatibility rules.
7726 --For property-based and design-chart this will be caught earlier. Even if it
7727 --gets here for these types of rules, the message is still relevant.
7728
7729 report_and_raise_rule_warning (
7730 p_text => CZ_UTILS.GET_TEXT(
7731 CZ_FCE_W_CT_INCOMPLETE_RULE,
7732 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name ),
7733 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path)),
7734 p_warning_location => 'verify_compatibility_table' );
7735
7736 END IF;
7737
7738 IF (( NOT p_emptiness ) AND p_compat_table.combinations.COUNT = 0 ) THEN
7739
7740 --#<verification>
7741 --Compatibility table should be not empty. This error can be actually raised here only for
7742 --property-based compatibility rules, not for desing chart or explicit compatibility, so
7743 --the message can be significantly enhanced with property-based specifics specifics.
7744
7745 -- No valid combinations. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
7746 report_and_raise_rule_warning (
7747 CZ_UTILS.GET_TEXT ( CZ_FCE_W_COMPAT_NO_COMB,
7748 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name ),
7749 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path)),
7750 'verify_compatibility_table'
7751 );
7752
7753 END IF;
7754
7755 --#<verification>
7756 --Only one of the participating features is allowed to have maximum > 1. When we call this procedure
7757 --on compat tables constructed for a design chart, there is a little overhead as the primary feature
7758 --participates in all these tables, and we end up checking its maximum several times.
7759
7760 l_count := 0;
7761
7762 FOR i IN 1..p_compat_table.participants.COUNT LOOP
7763
7764 l_index := h_psnid_backindex ( TO_CHAR ( p_compat_table.participants ( i ).ps_node_id ));
7765 hl_parentid ( TO_CHAR ( t_psn_parentid ( l_index ))) := 1;
7766
7767 l_maximum := CASE is_bom_node ( l_index ) WHEN TRUE THEN t_psn_maximumselected ( l_index ) ELSE t_psn_maximum ( l_index ) END;
7768
7769 IF ( l_maximum IS NULL OR l_maximum > 1 ) THEN
7770
7771 l_count := l_count + 1;
7772
7773 END IF;
7774 END LOOP;
7775
7776 --Verify for cyclic relationships in rule definition, when a participant is also a child of another
7777 --participant.
7778
7779 FOR i IN 1..p_compat_table.participants.COUNT LOOP
7780
7781 IF ( hl_parentid.EXISTS ( TO_CHAR ( p_compat_table.participants ( i ).ps_node_id ))) THEN
7782 -- Cyclic relationship between compatibility rule participants. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
7783 report_and_raise_rule_warning (
7784 p_text => CZ_UTILS.GET_TEXT(
7785 CZ_FCE_W_CT_CYCLIC_RELATION,
7786 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
7787 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path)),
7788 p_warning_location => 'verify_compatibility_table' );
7789
7790 END IF;
7791 END LOOP;
7792
7793 IF ( l_count > 1 ) THEN
7794 -- Only one participant of a compatibility rule is allowed to have non-mutually-exclusive children. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
7795 report_and_raise_rule_warning(
7796 p_text => CZ_UTILS.GET_TEXT(
7797 CZ_FCE_W_CT_ONLY_ONE_NON_MEXC,
7798 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
7799 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
7800 p_warning_location => 'verify_compatibility_table');
7801
7802 END IF;
7803
7804 --#<verification>
7805 --All the combination tuples must have the same size.
7806
7807 --#<optimization>
7808 --This verification may potentially be expensive if there are millions of combinations. As compatibility
7809 --table is built by the compiler itself this verification is not necessary and can be removed when there
7810 --are no bugs in this area.
7811
7812 IF ( p_compat_table.combinations.COUNT > 0 ) THEN
7813
7814 l_count := p_compat_table.combinations ( 1 ).COUNT;
7815
7816 FOR i IN 1..p_compat_table.combinations.COUNT LOOP
7817
7818 IF ( p_compat_table.combinations ( i ).COUNT <> l_count ) THEN
7819
7820 --Every combination should consist of the same number of options.
7821
7822 --#<should never happen>
7823 -- 'Incorrect size of a compatible combination occurred. Compatibility Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
7824 report_and_raise_rule_sys_warn(
7825 p_text => GET_NOT_TRANSLATED_TEXT(
7826 CZ_FCE_SW_CT_INCORRECT_SIZE ),
7827 p_warning_location => 'verify_compatibility_table');
7828
7829 END IF;
7830 END LOOP;
7831 END IF;
7832 END verify_compatibility_table;
7833 ----------------------------------------------------------------------------------
7834 -- Scope: compile_constraints
7835 FUNCTION get_table_reference ( p_data_type IN NUMBER
7836 , p_iterator_index IN PLS_INTEGER
7837 , p_property_index IN PLS_INTEGER
7838 ) RETURN VARCHAR2 IS
7839
7840 l_key VARCHAR2(4000);
7841
7842 BEGIN
7843
7844 l_key := p_iterator_index || ')(i' || p_iterator_index || ')(' || p_property_index || ')';
7845
7846 IF ( p_data_type IN ( h_datatypes ('integer'), h_datatypes ('decimal'))) THEN
7847
7848 RETURN 'cz_fce_compile.n_(' || l_key;
7849
7850 ELSIF ( p_data_type = h_datatypes ('boolean')) THEN
7851
7852 --We use integer representation of boolean as 0/1.
7853
7854 RETURN 'cz_fce_compile.b_(' || l_key;
7855
7856 ELSE
7857
7858 --For all other type (text and translatable) we use text.
7859
7860 RETURN 'cz_fce_compile.t_(' || l_key;
7861
7862 END IF;
7863 END get_table_reference;
7864 ----------------------------------------------------------------------------------
7865 -- Scope: compile_constraints
7866 FUNCTION lookup_parameter_value ( j IN PLS_INTEGER, l_property_id IN NUMBER ) RETURN VARCHAR2 IS
7867
7868 l_parameter type_iterator_value;
7869
7870 BEGIN
7871
7872 l_parameter := retrieve_parameter ( t_exp_argumentname ( j ));
7873
7874 CASE l_parameter.value_type WHEN const_valuetype_literal THEN
7875
7876 IF ( l_parameter.data_type IN ( h_datatypes ('integer'), h_datatypes ('decimal'))) THEN
7877
7878 RETURN l_parameter.data_num_value;
7879
7880 ELSE
7881
7882 RETURN l_parameter.data_value;
7883
7884 END IF;
7885
7886 WHEN const_valuetype_node THEN
7887
7888 RETURN get_property_value ( l_property_id, l_parameter.ps_node_id, l_parameter.model_ref_expl_id );
7889
7890 ELSE
7891 -- 'In paramater stack invalid value type ^VALUE_TYPE associated with the parameter "^PARAM". Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
7892 report_and_raise_rule_sys_warn(
7893 p_text => GET_NOT_TRANSLATED_TEXT(
7894 CZ_FCE_SW_INVAL_VAL_PARAMSTK,
7895 'VALUE_TYPE', l_parameter.value_type,
7896 'PARAM', t_exp_argumentname ( j ) ),
7897 p_warning_location => 'lookup_parameter_value');
7898 RETURN NULL;
7899 END CASE;
7900 END lookup_parameter_value;
7901 ----------------------------------------------------------------------------------
7902 -- Scope: compile_constraints
7903 PROCEDURE generate_parameter ( j IN PLS_INTEGER
7904 , p_input_context IN expression_context
7905 , x_output_context IN OUT NOCOPY expression_context
7906 ) IS
7907
7908 l_parameter type_iterator_value;
7909
7910 BEGIN
7911
7912 l_parameter := retrieve_parameter ( t_exp_argumentname ( j ));
7913
7914 CASE l_parameter.value_type WHEN const_valuetype_literal THEN
7915
7916 t_exp_datavalue ( j ) := l_parameter.data_value;
7917 t_exp_datanumvalue ( j ) := l_parameter.data_num_value;
7918 t_exp_datatype ( j ) := l_parameter.data_type;
7919
7920 t_exp_exprtype ( j ) := h_exprtypes ('literal');
7921
7922 generate_literal ( j, get_literal_value ( j ), l_parameter.data_type, p_input_context, x_output_context );
7923
7924 WHEN const_valuetype_variable THEN
7925
7926 aload_register ( l_parameter.data_value );
7927
7928 WHEN const_valuetype_sysprop THEN
7929
7930 generate_system_property ( l_parameter.data_num_value, l_parameter.ps_node_id, l_parameter.model_ref_expl_id, p_input_context, x_output_context );
7931
7932 WHEN const_valuetype_node THEN
7933
7934 t_exp_psnodeid ( j ) := l_parameter.ps_node_id;
7935 t_exp_modelrefexplid ( j ) := l_parameter.model_ref_expl_id;
7936
7937 t_exp_exprtype ( j ) := h_exprtypes ('node');
7938
7939 generate_structure_node ( j, p_input_context, x_output_context );
7940
7941 WHEN const_valuetype_selection THEN
7942
7943 t_exp_psnodeid ( j ) := l_parameter.ps_node_id;
7944 t_exp_modelrefexplid ( j ) := l_parameter.model_ref_expl_id;
7945
7946 IF ( h_exprid_childrenindex.EXISTS ( TO_CHAR ( t_exp_exprnodeid ( j )))) THEN
7947
7948 l_parameter.data_num_value := get_property_id ( h_exprid_childrenindex ( TO_CHAR ( t_exp_exprnodeid ( j ))));
7949
7950 END IF;
7951
7952 generate_selection ( j, l_parameter.data_num_value, p_input_context, x_output_context );
7953
7954 ELSE
7955 -- 'In paramater stack invalid value type ^VALUE_TYPE associated with the parameter "^PARAM". Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
7956 report_and_raise_rule_sys_warn(
7957 p_text => GET_NOT_TRANSLATED_TEXT(
7958 CZ_FCE_SW_INVAL_VAL_PARAMSTK,
7959 'VALUE_TYPE', l_parameter.value_type,
7960 'PARAM', t_exp_argumentname ( j ) ),
7961 p_warning_location => 'generate_parameter');
7962
7963 END CASE;
7964
7965 add_argument ( j );
7966
7967 END generate_parameter;
7968 ----------------------------------------------------------------------------------
7969 -- Scope: compile_constraints
7970 FUNCTION value_string ( j IN PLS_INTEGER
7971 , p_data_type IN NUMBER
7972 , p_num_value IN VARCHAR2
7973 , p_value IN VARCHAR2 ) RETURN VARCHAR2 IS
7974 BEGIN
7975
7976 IF ( p_data_type IN ( h_datatypes ('integer'), h_datatypes ('decimal'))) THEN
7977
7978 RETURN p_num_value;
7979
7980 ELSIF ( p_data_type = h_datatypes ('text')) THEN
7981
7982 RETURN '''' || p_value || '''';
7983
7984 ELSIF ( p_data_type = h_datatypes ('boolean')) THEN
7985
7986 --In cz_expression_nodes value of a boolean literal is represented by 0 or 1 in data_value.
7987 --Here we are trying to handle cases, when the user writes logical constants explicitly as
7988 --operands to logical operands, for example NOT FALSE.
7989
7990 IF ( logical_context ( j, NULL )) THEN
7991
7992 RETURN '(' || CASE p_value WHEN 0 THEN 'FALSE' ELSE 'TRUE' END || ')';
7993
7994 ELSE
7995
7996 RETURN p_value;
7997
7998 END IF;
7999
8000 ELSE
8001
8002 RETURN NVL ( p_num_value, '''' || p_value || '''' );
8003
8004 END IF;
8005 END value_string;
8006 ----------------------------------------------------------------------------------
8007 -- Scope: compile_constraints
8008 FUNCTION parse_where_clause ( j IN PLS_INTEGER
8009 , p_rule_type IN PLS_INTEGER
8010 , p_index_by_iterator IN OUT NOCOPY type_data_hashtable
8011 , p_property_by_iterator IN OUT NOCOPY type_datahashtable_table
8012 ) RETURN VARCHAR2 IS
8013
8014 l_property_id NUMBER;
8015 l_data_type NUMBER;
8016 l_value VARCHAR2(4000);
8017 l_key VARCHAR2(4000);
8018 l_expr_id VARCHAR2(4000);
8019
8020 l_index PLS_INTEGER;
8021 l_iterator_index PLS_INTEGER;
8022 l_property_index PLS_INTEGER;
8023
8024 BEGIN
8025
8026 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
8027
8028 IF ( t_exp_exprtype ( j ) IN ( h_exprtypes ('argument'), h_exprtypes ('node'))) THEN
8029
8030 IF ( p_rule_type = const_ruletype_compatible ) THEN
8031
8032 --This will get the property_id appropriately for user or system property.
8033
8034 IF ( expr_has_one_child ( l_expr_id )) THEN
8035
8036 l_index := h_exprid_childrenindex ( l_expr_id );
8037
8038 ELSE
8039
8040 report_and_raise_rule_sys_warn(
8041 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_SNODE_WHERE_LIMITS,
8042 'EXPR_ID', l_expr_id ),
8043 p_warning_location => 'parse_where_clause');
8044
8045 END IF;
8046
8047 END IF;
8048
8049 IF ( h_exprid_childrenindex.EXISTS ( l_expr_id )) THEN
8050
8051 l_property_id := get_property_id ( h_exprid_childrenindex ( l_expr_id ));
8052
8053 ELSE
8054
8055 --In a statement forall, iterator can participate in the where clause without any property applied.
8056 --In this case we use property_id = 0 and get data type from the parent operator.
8057
8058 l_property_id := get_property_id ( j );
8059
8060 END IF;
8061
8062 get_property_info ( l_property_id, l_data_type, l_value );
8063
8064 END IF;
8065
8066 CASE t_exp_exprtype ( j ) WHEN h_exprtypes ('argument') THEN
8067
8068 IF ( NOT p_index_by_iterator.EXISTS ( t_exp_argumentname ( j ))) THEN
8069
8070 --This is an iterator from an outer forall, need to evaluate it to a constant.
8071
8072 l_value := lookup_parameter_value ( j, l_property_id );
8073 RETURN value_string ( j, l_data_type, l_value, l_value );
8074
8075 ELSE
8076
8077 l_iterator_index := p_index_by_iterator ( t_exp_argumentname ( j ));
8078 l_key := TO_CHAR ( l_property_id );
8079
8080 IF ( p_property_by_iterator.EXISTS ( l_iterator_index ) AND p_property_by_iterator ( l_iterator_index ).EXISTS ( l_key )) THEN
8081
8082 l_property_index := p_property_by_iterator ( l_iterator_index )( l_key );
8083
8084 ELSIF ( NOT p_property_by_iterator.EXISTS ( l_iterator_index )) THEN
8085
8086 p_property_by_iterator ( l_iterator_index )( l_key ) := 1;
8087 l_property_index := 1;
8088
8089 ELSE
8090
8091 l_property_index := p_property_by_iterator ( l_iterator_index ).COUNT + 1;
8092 p_property_by_iterator ( l_iterator_index )( l_key ) := l_property_index;
8093
8094 END IF;
8095
8096 --Depending on the data type, generate reference to corresponding table.
8097
8098 RETURN get_table_reference ( l_data_type, l_iterator_index, l_property_index );
8099
8100 END IF;
8101
8102 WHEN h_exprtypes ('node') THEN
8103
8104 l_value := get_property_value ( l_property_id, t_exp_psnodeid ( j ), t_exp_modelrefexplid ( j ));
8105 RETURN value_string ( j, l_data_type, l_value, l_value );
8106
8107 WHEN h_exprtypes ('literal') THEN
8108
8109 RETURN value_string ( j, t_exp_datatype ( j ), TO_CHAR ( t_exp_datanumvalue ( j )), t_exp_datavalue ( j ));
8110
8111 WHEN h_exprtypes ('operator') THEN
8112
8113 IF ( t_exp_templateid ( j ) IN
8114 ( h_templates ('and')
8115 , h_templates ('or')
8116 , h_templates ('equals')
8117 , h_templates ('notequals')
8118 , h_templates ('gt')
8119 , h_templates ('lt')
8120 , h_templates ('ge')
8121 , h_templates ('le')
8122 , h_templates ('add')
8123 , h_templates ('subtract')
8124 , h_templates ('multiply')
8125 , h_templates ('div')
8126 , h_templates ('doesnotbeginwith')
8127 , h_templates ('doesnotendwith')
8128 , h_templates ('doesnotcontain')
8129 , h_templates ('notlike')
8130 , h_templates ('concatenate')
8131 , h_templates ('beginswith')
8132 , h_templates ('endswith')
8133 , h_templates ('contains')
8134 , h_templates ('like')
8135 , h_templates ('matches')
8136 , h_templates ('textequals')
8137 , h_templates ('textnotequals')
8138 )) THEN
8139
8140 IF ( expr_has_two_children ( l_expr_id )) THEN
8141
8142 l_index := h_exprid_childrenindex ( l_expr_id );
8143
8144 ELSE
8145
8146 report_and_raise_rule_sys_warn(
8147 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_RE_ENODE_TWO_CHILD,
8148 'EXPR_ID', l_expr_id ),
8149 p_warning_location => 'parse_where_clause');
8150
8151 END IF;
8152
8153 RETURN parse_operator ( parse_where_clause ( l_index, p_rule_type, p_index_by_iterator, p_property_by_iterator )
8154 , t_exp_templateid ( j )
8155 , parse_where_clause ( l_index + 1, p_rule_type, p_index_by_iterator, p_property_by_iterator )
8156 );
8157
8158 ELSIF ( t_exp_templateid ( j ) IN
8159 ( h_templates ('totext')
8160 , h_templates ('not')
8161 , h_templates ('neg')
8162 )) THEN
8163
8164 IF ( expr_has_one_child ( l_expr_id )) THEN
8165
8166 l_index := h_exprid_childrenindex ( l_expr_id );
8167
8168 ELSE
8169
8170 report_and_raise_rule_sys_warn(
8171 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_RE_ENODE_ONE_CHILD,
8172 'EXPR_ID', l_expr_id ),
8173 p_warning_location => 'parse_where_clause');
8174
8175 END IF;
8176
8177 RETURN parse_operator ( parse_where_clause ( l_index, p_rule_type, p_index_by_iterator, p_property_by_iterator )
8178 , t_exp_templateid ( j ), NULL );
8179
8180 ELSE
8181
8182 -- 'Unknown operator in the WHERE clause. Rule "^RULE_NAME" in the Model "^MODEL_NAME" ignored.';
8183
8184 report_and_raise_rule_sys_warn(
8185 GET_NOT_TRANSLATED_TEXT(CZ_FCE_SW_UKNOWN_OP_IN_COMPAT),
8186 'parse_where_clause'
8187 );
8188 RETURN NULL;
8189
8190 END IF;
8191
8192 ELSE
8193
8194 -- 'Unknown expression node type in the WHERE clause, expr_node_id "^EXPR_ID". Rule ^RULE_NAME in the model ^MODEL_NAME ignored.';
8195
8196 report_and_raise_rule_sys_warn(
8197 p_text => GET_NOT_TRANSLATED_TEXT(
8198 CZ_FCE_SW_INVAL_E_ID_IN_WHERE,
8199 'EXPR_ID', l_expr_id ),
8200 p_warning_location => 'parse_where_clause');
8201 RETURN NULL;
8202
8203 END CASE;
8204 END parse_where_clause;
8205 ----------------------------------------------------------------------------------
8206 -- Scope: compile_constraints
8207 PROCEDURE generate_statement_forall ( j IN PLS_INTEGER
8208 , p_input_context IN expression_context
8209 , x_output_context IN OUT NOCOPY expression_context
8210 ) IS
8211
8212 l_index PLS_INTEGER;
8213 l_expr_index PLS_INTEGER;
8214 l_expression_index PLS_INTEGER;
8215 l_where_index PLS_INTEGER;
8216 l_property_index PLS_INTEGER;
8217 l_count PLS_INTEGER;
8218
8219 l_parsed VARCHAR2(32000);
8220 l_expr_id VARCHAR2(4000);
8221 l_key VARCHAR2(4000);
8222 l_value VARCHAR2(4000);
8223
8224 l_data_type NUMBER;
8225 l_property_id NUMBER;
8226
8227 h_index_by_iterator type_data_hashtable;
8228 h_property_by_iterator type_datahashtable_table;
8229 t_iterator_table type_iteratortable_table;
8230 l_iterator type_iterator_table;
8231 t_argument_table type_varchar4000_table;
8232 h_distinct_values type_data_hashtable;
8233
8234 l_compat type_compat_table;
8235
8236 l_distinct BOOLEAN;
8237 l_embedded BOOLEAN;
8238 l_iterator_collect BOOLEAN;
8239 ----------------------------------------------------------------------------------
8240 -- Scope: generate_statement_forall
8241 FUNCTION generate_iterator ( j IN PLS_INTEGER ) RETURN type_iterator_table IS
8242
8243 l_expr_id VARCHAR2(4000);
8244 l_property_id NUMBER;
8245 l_data_type NUMBER;
8246 l_value VARCHAR2(4000);
8247
8248 l_index PLS_INTEGER;
8249 l_count PLS_INTEGER;
8250 l_child PLS_INTEGER;
8251 l_node_index PLS_INTEGER;
8252
8253 l_iterator type_iterator_table;
8254 t_children type_iteratornode_table;
8255
8256 l_input_context expression_context;
8257 l_output_context expression_context;
8258
8259 BEGIN
8260
8261 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
8262
8263 IF ( expr_has_children ( l_expr_id )) THEN
8264
8265 l_index := h_exprid_childrenindex ( l_expr_id );
8266
8267 ELSE
8268
8269 -- 'Incomplete forall rule, empty iterator. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
8270 report_and_raise_rule_sys_warn (
8271 p_text => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SW_INCOMPLETE_FORALL ),
8272 p_warning_location => 'generate_iterator');
8273
8274 END IF;
8275
8276 WHILE ( t_exp_exprparentid.EXISTS ( l_index ) AND t_exp_exprparentid ( l_index ) = t_exp_exprnodeid ( j )) LOOP
8277
8278 l_count := l_iterator.COUNT + 1;
8279 t_children.DELETE;
8280
8281 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( l_index ));
8282
8283 IF ( t_exp_exprtype ( l_index ) IN ( h_exprtypes ('forall'), h_exprtypes ('foralldistinct'))) THEN
8284
8285 generate_statement_forall ( l_index, l_input_context, l_output_context );
8286
8287 FOR i IN 1..c_.combinations.COUNT LOOP
8288
8289 --This is a COLLECT in the iterator, there can be only one iterator in it and the expression
8290 --should resolve to a literal.
8291
8292 l_iterator ( l_count ) := c_.combinations ( i )( 1 );
8293 l_count := l_count + 1;
8294
8295 END LOOP;
8296
8297 ELSIF ( h_exprid_childrenindex.EXISTS ( l_expr_id )) THEN
8298
8299 l_child := h_exprid_childrenindex ( l_expr_id );
8300
8301 --A strange way to identify options operator or property.
8302
8303 IF (( t_exp_exprtype ( l_index ) = h_exprtypes ('operator') AND t_exp_templateid ( l_index ) = h_templates ('optionsof')) OR
8304 ( t_exp_exprtype ( l_child ) = h_exprtypes ('systemproperty') AND t_exp_templateid ( l_child ) = h_templates ('options'))) THEN
8305
8306 l_node_index := CASE t_exp_exprtype ( l_index ) WHEN h_exprtypes ('operator') THEN l_child ELSE l_index END;
8307 t_children := explode_node_children ( t_exp_psnodeid ( l_node_index ), t_exp_modelrefexplid ( l_node_index ), FALSE );
8308
8309 FOR i IN 1..t_children.COUNT LOOP
8310
8311 l_iterator ( l_count ).value_type := const_valuetype_node;
8312 l_iterator ( l_count ).ps_node_id := t_children ( i ).ps_node_id;
8313 l_iterator ( l_count ).model_ref_expl_id := t_children ( i ).model_ref_expl_id;
8314
8315 l_count := l_count + 1;
8316
8317 END LOOP;
8318
8319 ELSE
8320
8321 IF ( t_exp_psnodeid ( l_index ) IS NULL ) THEN
8322
8323 --User or system property can be applied only to a structure node.
8324
8325 report_and_raise_rule_warning(
8326 p_text => GET_NOT_TRANSLATED_TEXT(
8327 CZ_FCE_SW_INVALID_PROP_USAGE),
8328 p_warning_location => 'generate_iterator');
8329
8330 END IF;
8331
8332 l_property_id := get_property_id ( l_child );
8333
8334 IF ( h_runtime_properties.EXISTS ( l_property_id )) THEN
8335
8336 --Bug #7348938. We used to generate the expression right here and store the result
8337 --in iterator value of type variable. Later this variable would be aloaded when
8338 --generating the forall expression. We could do that because such iterator values
8339 --cannot participate in the WHERE clause and so we could forget about them until
8340 --the forall expression is generated. However, this does not work for accumulator
8341 --rules because target should be generated BEFORE contributors, and so we cannot
8342 --generate contributors here.
8343
8344 l_iterator ( l_count ).value_type := const_valuetype_sysprop;
8345 l_iterator ( l_count ).ps_node_id := t_exp_psnodeid ( l_index );
8346 l_iterator ( l_count ).model_ref_expl_id := t_exp_modelrefexplid ( l_index );
8347 l_iterator ( l_count ).data_num_value := l_property_id;
8348
8349 ELSIF ( l_property_id = h_templates ('selection')) THEN
8350
8351 l_iterator ( l_count ).value_type := const_valuetype_selection;
8352 l_iterator ( l_count ).ps_node_id := t_exp_psnodeid ( l_index );
8353 l_iterator ( l_count ).model_ref_expl_id := t_exp_modelrefexplid ( l_index );
8354
8355 l_child := l_child + 1;
8356
8357 IF ( t_exp_exprparentid.EXISTS ( l_child ) AND t_exp_exprparentid ( l_child ) = t_exp_exprnodeid ( l_index )) THEN
8358
8359 l_iterator ( l_count ).data_num_value := get_property_id ( l_child );
8360
8361 END IF;
8362
8363 ELSE
8364
8365 l_iterator ( l_count ).value_type := const_valuetype_literal;
8366
8367 get_property_info ( l_property_id, l_data_type, l_value );
8368 l_value := get_property_value ( l_property_id, t_exp_psnodeid ( l_index ), t_exp_modelrefexplid ( l_index ));
8369
8370 l_iterator ( l_count ).data_type := l_data_type;
8371
8372 IF ( l_data_type IN ( h_datatypes ('integer'), h_datatypes ('decimal'))) THEN
8373
8374 l_iterator ( l_count ).data_num_value := TO_NUMBER ( l_value );
8375
8376 ELSE
8377
8378 l_iterator ( l_count ).data_value := l_value;
8379
8380 END IF;
8381 END IF;
8382 END IF;
8383
8384 ELSIF ( t_exp_exprtype ( l_index ) = h_exprtypes ('literal')) THEN
8385
8386 l_iterator ( l_count ).value_type := const_valuetype_literal;
8387 l_iterator ( l_count ).data_type := t_exp_datatype ( l_index );
8388
8389 IF ( t_exp_datatype ( l_index ) IN ( h_datatypes ('integer'), h_datatypes ('decimal'))) THEN
8390
8391 l_iterator ( l_count ).data_num_value := t_exp_datanumvalue ( l_index );
8392
8393 ELSE
8394
8395 l_iterator ( l_count ).data_value := t_exp_datavalue ( l_index );
8396
8397 END IF;
8398
8399 ELSIF ( t_exp_exprtype ( l_index ) = h_exprtypes ('node')) THEN
8400
8401 l_iterator ( l_count ).value_type := const_valuetype_node;
8402 l_iterator ( l_count ).ps_node_id := t_exp_psnodeid ( l_index );
8403 l_iterator ( l_count ).model_ref_expl_id := t_exp_modelrefexplid ( l_index );
8404
8405 ELSE
8406
8407 --#<should never happen>
8408 report_and_raise_rule_sys_warn(
8409 p_text => GET_NOT_TRANSLATED_TEXT(
8410 CZ_FCE_SW_INVALID_EXPR_NODE,
8411 'EXPR_TYPE', t_exp_exprtype ( l_index ) ),
8412 p_warning_location => 'generate_iterator');
8413
8414 END IF;
8415
8416 l_index := l_index + 1;
8417
8418 END LOOP;
8419
8420 RETURN l_iterator;
8421 END generate_iterator;
8422 ----------------------------------------------------------------------------------
8423 BEGIN
8424
8425 l_distinct := ( t_exp_exprtype ( j ) = h_exprtypes ('foralldistinct'));
8426 l_embedded := ( t_exp_exprparentid ( j ) IS NOT NULL );
8427 l_iterator_collect := ( l_embedded AND t_exp_exprtype ( h_exprid_backindex ( TO_CHAR ( t_exp_exprparentid ( j )))) = h_exprtypes ('iterator'));
8428
8429 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
8430
8431 IF ( expr_has_children ( l_expr_id )) THEN
8432
8433 l_index := h_exprid_childrenindex ( l_expr_id ) - 1;
8434
8435 ELSE
8436
8437 report_and_raise_rule_sys_warn (
8438 p_text => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SW_RE_ENODE_CHILDREN,
8439 'EXPR_ID', l_expr_id ),
8440 p_warning_location => 'generate_statement_forall');
8441
8442 END IF;
8443
8444 l_where_index := 0;
8445
8446 --Find iterator definition indexes and WHERE clause index, and generate all iterators.
8447
8448 FOR i IN 1..h_exprid_numberofchildren ( l_expr_id ) LOOP
8449
8450 l_expr_index := l_index + i;
8451
8452 CASE t_exp_exprtype ( l_expr_index ) WHEN h_exprtypes ('iterator') THEN
8453
8454 h_index_by_iterator ( t_exp_argumentname ( l_expr_index )) := h_index_by_iterator.COUNT + 1;
8455
8456 t_iterator_table ( t_iterator_table.COUNT + 1 ) := generate_iterator ( l_expr_index );
8457 t_argument_table ( t_argument_table.COUNT + 1 ) := t_exp_argumentname ( l_expr_index );
8458
8459 WHEN h_exprtypes ('where') THEN
8460
8461 IF ( expr_has_children ( TO_CHAR ( t_exp_exprnodeid ( l_expr_index )))) THEN
8462
8463 l_where_index := h_exprid_childrenindex ( TO_CHAR ( t_exp_exprnodeid ( l_expr_index )));
8464
8465 ELSE
8466
8467 report_and_raise_rule_sys_warn (
8468 p_text => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SW_RE_ENODE_CHILDREN,
8469 'EXPR_ID', TO_CHAR ( t_exp_exprnodeid ( l_expr_index ))),
8470 p_warning_location => 'generate_logic_template');
8471
8472 END IF;
8473
8474 ELSE
8475
8476 l_expression_index := l_expr_index;
8477
8478 END CASE;
8479 END LOOP;
8480
8481 IF ( l_where_index <> 0 ) THEN
8482
8483 l_parsed := parse_where_clause ( l_where_index, const_ruletype_forall, h_index_by_iterator, h_property_by_iterator );
8484
8485 END IF;
8486
8487 IF ( t_iterator_table.COUNT = 0 ) THEN
8488
8489 --#<should never happen>
8490 -- 'Incomplete forall rule, empty iterator. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
8491
8492 report_and_raise_rule_sys_warn(
8493 p_text => GET_NOT_TRANSLATED_TEXT(
8494 CZ_FCE_SW_INCOMPLETE_FORALL ),
8495 p_warning_location => 'generate_statement_forall');
8496
8497 END IF;
8498
8499 IF ( l_distinct AND t_iterator_table.COUNT > 1 ) THEN
8500
8501 -- DISTINCT COLLECT and FOR ALL operations are not supported when there is more than one iterator. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
8502
8503 report_and_raise_rule_warning(
8504 p_text => CZ_UTILS.GET_TEXT (
8505 CZ_FCE_W_MORE_THAN_ONE_IT_LIM,
8506 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name ),
8507 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH (p_component_id, p_model_path)),
8508 p_warning_location => 'generate_statement_forall');
8509
8510 END IF;
8511
8512 c_.participants.DELETE;
8513 c_.combinations.DELETE;
8514
8515 o_.DELETE;
8516 n_.DELETE;
8517 s_.DELETE;
8518 t_.DELETE;
8519 b_.DELETE;
8520
8521 FOR i IN 1..t_iterator_table.COUNT LOOP
8522
8523 s_( i ) := t_iterator_table ( i ).COUNT;
8524
8525 l_iterator := t_iterator_table ( i );
8526 o_( i ) := l_iterator;
8527
8528 FOR ii IN 1..s_( i ) LOOP
8529
8530 IF ( l_parsed IS NOT NULL AND h_property_by_iterator.EXISTS ( i )) THEN
8531
8532 --h_property_by_iterator ( i ) value would exist only for iterators that are referenced
8533 --in the WHERE clause. If an iterator is not referenced, we don't need it here.
8534
8535 l_key := h_property_by_iterator ( i ).FIRST;
8536
8537 WHILE ( l_key IS NOT NULL ) LOOP
8538
8539 l_property_id := TO_NUMBER ( l_key );
8540 l_property_index := h_property_by_iterator ( i )( l_key );
8541 get_property_info ( l_property_id, l_data_type, l_value );
8542
8543 --Populate corresponding arrays if there is a WHERE clause.
8544
8545 IF ( l_property_id IN ( h_datatypes ('decimal'), h_datatypes ('boolean'), h_datatypes ('text'))) THEN
8546
8547 --Iterator is referenced without any property applied.
8548
8549 IF ( l_data_type IN ( h_datatypes ('integer'), h_datatypes ('decimal'))) THEN
8550
8551 --The iterator was referenced in the where clause without explicit property applied.
8552 --For now, allow this only for literals. Later we can set up applying 'default'
8553 --properties for nodes. However, applying default would be equivalent to allowing
8554 --dynamic properties in the where clause, because default property is either State()
8555 --or Quantity(), so we probably will not do that.
8556
8557 IF ( l_iterator ( ii ).value_type <> const_valuetype_literal ) THEN
8558
8559 -- Incorrect COLLECT or FOR ALL Rule: The conditional expression in the WHERE clause must be static. A dynamic source for
8560 -- a value provided for iterator ^ITER was detected. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
8561
8562 report_and_raise_rule_warning(
8563 p_text => CZ_UTILS.GET_TEXT (
8564 CZ_FCE_W_DYNAMIC_ITERATOR,
8565 'ITER', t_argument_table ( i ),
8566 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name ),
8567 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH ( p_component_id, p_model_path )),
8568 p_warning_location => 'generate_statement_forall');
8569
8570 END IF;
8571
8572 --Need the case below because boolean literals can participate in numeric context
8573 --and so the data type of the implicit property would be assumed as numeric.
8574
8575 n_( i )( ii )( l_property_index ) :=
8576 CASE l_iterator ( ii ).data_type
8577 WHEN h_datatypes ('boolean') THEN TO_NUMBER ( l_iterator ( ii ).data_value )
8578 ELSE l_iterator ( ii ).data_num_value END;
8579
8580 ELSIF ( l_data_type = h_datatypes ('boolean')) THEN
8581
8582 --We use integer representation of boolean as 0/1.
8583
8584 b_( i )( ii )( l_property_index ) := TO_NUMBER ( l_iterator ( ii ).data_value );
8585
8586 ELSE
8587
8588 --For all other types (text and translatable) we use text.
8589
8590 t_( i )( ii )( l_property_index ) := l_iterator ( ii ).data_value;
8591
8592 END IF;
8593
8594 ELSE
8595
8596 --This is an actual system or user property. It can only be applied to a node.
8597 --Later this verification can be removed.
8598
8599 IF ( l_iterator ( ii ).value_type <> const_valuetype_node ) THEN
8600
8601 --#<should never happen>
8602 -- 'Found invalid iterator value type "^VALUE". Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
8603 report_and_raise_rule_sys_warn(
8604 p_text => GET_NOT_TRANSLATED_TEXT(
8605 CZ_FCE_SW_INVALID_IT_VALUE,
8606 'VALUE', l_iterator ( ii ).value_type),
8607 p_warning_location => 'generate_statement_forall');
8608
8609 END IF;
8610
8611 l_value := get_property_value ( l_property_id, l_iterator ( ii ).ps_node_id, l_iterator (ii).model_ref_expl_id );
8612
8613 IF ( l_data_type IN ( h_datatypes ('integer'), h_datatypes ('decimal'))) THEN
8614
8615 n_( i )( ii )( l_property_index ) := TO_NUMBER ( l_value );
8616
8617 ELSIF ( l_data_type = h_datatypes ('boolean')) THEN
8618
8619 --We use integer representation of boolean as 0/1.
8620
8621 b_( i )( ii )( l_property_index ) := TO_NUMBER ( l_value );
8622
8623 ELSE
8624
8625 --For all other types (text and translatable) we use text.
8626
8627 t_( i )( ii )( l_property_index ) := l_value;
8628
8629 END IF;
8630 END IF;
8631
8632 l_key := h_property_by_iterator ( i ).NEXT ( l_key );
8633
8634 END LOOP;
8635 END IF;
8636 END LOOP;
8637 END LOOP;
8638
8639 EXECUTE IMMEDIATE build_executable ( t_iterator_table.COUNT, l_parsed );
8640
8641 IF ( l_iterator_collect ) THEN
8642
8643 --This is a collect within an iterator of an outer forall, it can only have single
8644 --iterator, and the expression can only be the iterator with or without static
8645 --property applied.
8646
8647 IF ( h_exprid_childrenindex.EXISTS ( t_exp_exprnodeid ( l_expression_index ))) THEN
8648
8649 l_property_id := get_property_id ( h_exprid_childrenindex ( t_exp_exprnodeid ( l_expression_index )));
8650 get_property_info ( l_property_id, l_data_type, l_value );
8651
8652 FOR i IN 1..c_.combinations.COUNT LOOP
8653
8654 l_value := get_property_value ( l_property_id, c_.combinations ( i )( 1 ).ps_node_id, c_.combinations ( i )( 1 ).model_ref_expl_id );
8655
8656 c_.combinations ( i )( 1 ).value_type := const_valuetype_literal;
8657 c_.combinations ( i )( 1 ).data_type := l_data_type;
8658
8659 IF ( l_data_type IN ( h_datatypes ('integer'), h_datatypes ('decimal'))) THEN
8660
8661 c_.combinations ( i )( 1 ).data_num_value := TO_NUMBER ( l_value );
8662
8663 ELSE
8664
8665 c_.combinations ( i )( 1 ).data_value := l_value;
8666
8667 END IF;
8668 END LOOP;
8669
8670 IF ( l_distinct ) THEN
8671
8672 l_compat := c_;
8673 c_.combinations.DELETE;
8674
8675 l_count := 1;
8676
8677 FOR i IN 1..l_compat.combinations.COUNT LOOP
8678
8679 IF ( l_compat.combinations ( i )( 1 ).value_type <> const_valuetype_literal ) THEN
8680 -- 'Found non-literal value type in COLLECT DISTINCT. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
8681 report_and_raise_rule_sys_warn(
8682 p_text => GET_NOT_TRANSLATED_TEXT(
8683 CZ_FCE_SW_NON_LIT_IN_COLLECT),
8684 p_warning_location => 'generate_statement_forall');
8685
8686 END IF;
8687
8688 IF ( l_compat.combinations ( i )( 1 ).data_type IN ( h_datatypes ('integer'), h_datatypes ('decimal'))) THEN
8689
8690 l_value := TO_CHAR ( l_compat.combinations ( i )( 1 ).data_num_value );
8691
8692 ELSE
8693
8694 l_value := l_compat.combinations ( i )( 1 ).data_value;
8695
8696 END IF;
8697
8698 IF ( NOT h_distinct_values.EXISTS ( l_value )) THEN
8699
8700 c_.combinations ( l_count )( 1 ) := l_compat.combinations ( i )( 1 );
8701 l_count := l_count + 1;
8702
8703 h_distinct_values ( l_value ) := 1;
8704
8705 END IF;
8706 END LOOP;
8707 END IF;
8708 END IF;
8709
8710 RETURN;
8711 END IF;
8712
8713 --Need to copy the result to the local table because of the possibility of embedding.
8714
8715 l_compat := c_;
8716
8717 IF ( l_embedded ) THEN
8718
8719 --The forall is not on the top level so it is a collect. We will not add generated
8720 --expressions as constrains just generate them as arguments to the parent operator,
8721 --therefore we need to adjust the number of children of this operator.
8722
8723 l_expr_id := TO_CHAR ( t_exp_exprparentid ( j ));
8724 h_exprid_numberofchildren ( l_expr_id ) := h_exprid_numberofchildren ( l_expr_id ) - 1;
8725
8726 END IF;
8727
8728 l_count := h_parameter_stack.COUNT + 1;
8729
8730 FOR i IN 1..l_compat.combinations.COUNT LOOP
8731
8732 --Put each value from the combination into the parameter stack.
8733
8734 FOR ii IN 1..t_iterator_table.COUNT LOOP
8735
8736 h_parameter_stack ( l_count )( t_argument_table ( ii )) := l_compat.combinations ( i )( ii );
8737
8738 END LOOP;
8739
8740 clear_argument_table ();
8741
8742 IF ( NOT l_embedded ) THEN
8743
8744 --This is a top-level forall, generate it as a set of constraints.
8745
8746 h_instancequantifiers.DELETE;
8747 t_instancequantifiers.DELETE;
8748
8749 --Put the ModelDef on the stack for the last addConstraint call.
8750
8751 aload_model_def ( p_component_id );
8752 generate_expression ( l_expression_index, p_input_context, x_output_context );
8753
8754 IF (l_output_context.context_type NOT IN ( const_context_accumulation, const_context_heuristics )) THEN
8755
8756 set_reason_id ();
8757 add_constraint ();
8758
8759 ELSE
8760
8761 --In case of accumulator rule, we need to remove the model def, put on the stack
8762 --before expression generation, as we did not add the constraint yet.
8763 --In the case of ForAll all the constraints are already added so we also need to
8764 --remove the model def.
8765
8766 emit_pop ( 1 );
8767
8768 END IF;
8769
8770 ELSE
8771
8772 --The forall is not on the top level, therefore it is a collect.
8773
8774 generate_expression ( l_expression_index, p_input_context, x_output_context );
8775 h_exprid_numberofchildren ( l_expr_id ) := h_exprid_numberofchildren ( l_expr_id ) + 1;
8776
8777 END IF;
8778
8779 --When generating parameters, we change the expression type of parameter node to the
8780 --type of the retrieved argument and keep it during the expression generation. After
8781 --that we need to restore the argument type for the next iteration.
8782
8783 restore_arguments ();
8784
8785 END LOOP;
8786
8787 h_parameter_stack.DELETE ( l_count );
8788 x_output_context.context_type := const_context_forall;
8789
8790 END generate_statement_forall;
8791 ----------------------------------------------------------------------------------
8792 -- Scope: compile_constraints
8793 PROCEDURE generate_compatible ( j IN PLS_INTEGER
8794 , p_input_context IN expression_context
8795 , x_output_context IN OUT NOCOPY expression_context
8796 ) IS
8797
8798 l_property_index PLS_INTEGER;
8799 l_data_type NUMBER;
8800 l_property_id NUMBER;
8801 l_key VARCHAR2(4000);
8802 l_value VARCHAR2(4000);
8803 l_parsed VARCHAR2(32000);
8804
8805 h_index_by_iterator type_data_hashtable;
8806 h_property_by_iterator type_datahashtable_table;
8807 t_children type_iteratornode_table;
8808 ----------------------------------------------------------------------------------
8809 -- Scope: generate_compatible
8810 FUNCTION parse_template_application ( j IN PLS_INTEGER ) RETURN VARCHAR2 IS
8811
8812 l_index PLS_INTEGER;
8813 l_expr_index PLS_INTEGER;
8814 l_operator PLS_INTEGER;
8815 l_expr_id VARCHAR2(4000);
8816
8817 l_property_id NUMBER;
8818 l_data_type NUMBER;
8819 l_def_value VARCHAR2(4000);
8820
8821 l_left_key VARCHAR2(4000);
8822 l_right_key VARCHAR2(4000);
8823
8824 l_if VARCHAR2(32000);
8825
8826 BEGIN
8827
8828 --This procedure parses a simple Property-based Compatibility template application
8829 --and prepares memory tables necessary for generation.
8830 --It returns the 'if' condition generated from the 'where' clause.
8831
8832 --The template application specifies the following parameters:
8833
8834 -- param_index = 1: first participant
8835 -- param_index = 2: property applied to the first participant
8836 -- param_index = 3: compatibility operator
8837 -- param_index = 4: second participant
8838 -- param_index = 5: property applied to the second participant
8839
8840 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
8841
8842 IF ( expr_has_children ( l_expr_id )) THEN
8843
8844 l_index := h_exprid_childrenindex ( l_expr_id ) - 1;
8845
8846 ELSE
8847
8848 -- Incomplete simple Property-based Compatibility rule. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
8849 report_and_raise_rule_warning (
8850 p_text => CZ_UTILS.GET_TEXT(
8851 CZ_FCE_W_INCOMPLETE_PROPBASED,
8852 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
8853 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path)),
8854 p_warning_location => 'parse_template_application');
8855
8856 END IF;
8857
8858 --Parse the template application.
8859
8860 FOR i IN 1..h_exprid_numberofchildren ( l_expr_id ) LOOP
8861
8862 l_expr_index := l_index + i;
8863
8864 CASE t_exp_paramindex ( l_expr_index )
8865
8866 WHEN 1 THEN
8867
8868 --First participant.
8869 -- 'Invalid parameter of type "^EXPR_TYPE" specified for the "^ARG_LOCATION" argument of the property-based compatibility template application. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
8870 IF ( t_exp_exprtype ( l_expr_index ) <> h_exprtypes ('node')) THEN
8871
8872 report_and_raise_rule_sys_warn(
8873 p_text => GET_NOT_TRANSLATED_TEXT(
8874 CZ_FCE_SW_INVALID_ARG_PARAM,
8875 'EXPR_TYPE', t_exp_exprtype ( l_expr_index ),
8876 'ARG_LOCATION', 'first' ),
8877 p_warning_location => 'parse_template_application');
8878
8879 END IF;
8880
8881 c_.participants ( 1 ).ps_node_id := t_exp_psnodeid ( l_expr_index );
8882 c_.participants ( 1 ).model_ref_expl_id := t_exp_modelrefexplid ( l_expr_index );
8883
8884 WHEN 2 THEN
8885
8886 --First property.
8887
8888 IF ( t_exp_exprtype ( l_expr_index ) NOT IN ( h_exprtypes ('literal'), h_exprtypes ('property'), h_exprtypes ('systemproperty'))) THEN
8889 -- 'Invalid parameter of type "^EXPR_TYPE" specified for the "^ARG_LOCATION" argument of the property-based compatibility template application. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
8890 report_and_raise_rule_sys_warn(
8891 p_text => GET_NOT_TRANSLATED_TEXT(
8892 CZ_FCE_SW_INVALID_ARG_PARAM,
8893 'EXPR_TYPE', t_exp_exprtype ( l_expr_index ),
8894 'ARG_LOCATION', 'second' ),
8895 p_warning_location => 'parse_template_application');
8896
8897 ELSIF ( t_exp_exprtype ( l_expr_index ) = h_exprtypes ('literal') AND t_exp_propertyid ( i ) IS NULL ) THEN
8898 -- 'Property is not defined. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
8899 report_and_raise_rule_sys_warn(
8900 p_text => GET_NOT_TRANSLATED_TEXT(
8901 CZ_FCE_SW_PROP_NOT_DEFINED,
8902 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name)),
8903 p_warning_location => 'parse_template_application');
8904
8905 END IF;
8906
8907 l_property_id := get_property_id ( l_expr_index );
8908 get_property_info ( l_property_id, l_data_type, l_def_value );
8909
8910 h_property_by_iterator ( 1 )( TO_CHAR ( l_property_id )) := 1;
8911 l_left_key := get_table_reference ( l_data_type, 1, 1 );
8912
8913 WHEN 3 THEN
8914
8915 --The operator is specified by name.
8916
8917 IF ( t_exp_exprtype ( l_expr_index ) NOT IN ( h_exprtypes ('template'), h_exprtypes ('operator'), h_exprtypes ('operatorbyname'))) THEN
8918 -- 'Invalid parameter of type "^EXPR_TYPE" specified for the "^ARG_LOCATION" argument of the property-based compatibility template application. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
8919 report_and_raise_rule_sys_warn(
8920 p_text => GET_NOT_TRANSLATED_TEXT(
8921 CZ_FCE_SW_INVALID_ARG_PARAM,
8922 'EXPR_TYPE', t_exp_exprtype ( l_expr_index ),
8923 'ARG_LOCATION', 'third' ),
8924 p_warning_location => 'parse_template_application');
8925
8926 END IF;
8927
8928 l_operator := CASE t_exp_exprtype ( l_expr_index )
8929 WHEN h_exprtypes ('operatorbyname') THEN h_templates ( LOWER ( t_exp_argumentname ( l_expr_index )))
8930 ELSE t_exp_templateid ( l_expr_index ) END;
8931
8932 WHEN 4 THEN
8933
8934 --Second participant.
8935
8936 IF ( t_exp_exprtype ( l_expr_index ) <> h_exprtypes ('node')) THEN
8937 -- 'Invalid parameter of type "^EXPR_TYPE" specified for the "^ARG_LOCATION" argument of the property-based compatibility template application. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
8938 report_and_raise_rule_sys_warn(
8939 p_text => GET_NOT_TRANSLATED_TEXT(
8940 CZ_FCE_SW_INVALID_ARG_PARAM,
8941 'EXPR_TYPE', t_exp_exprtype ( l_expr_index ),
8942 'ARG_LOCATION', 'forth' ),
8943 p_warning_location => 'parse_template_application');
8944
8945 END IF;
8946
8947 c_.participants ( 2 ).ps_node_id := t_exp_psnodeid ( l_expr_index );
8948 c_.participants ( 2 ).model_ref_expl_id := t_exp_modelrefexplid ( l_expr_index );
8949
8950 WHEN 5 THEN
8951
8952 --Second property.
8953
8954 IF ( t_exp_exprtype ( l_expr_index ) NOT IN ( h_exprtypes ('literal'), h_exprtypes ('property'), h_exprtypes ('systemproperty'))) THEN
8955 -- 'Invalid parameter of type "^EXPR_TYPE" specified for the "^ARG_LOCATION" argument of the property-based compatibility template application. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
8956 report_and_raise_rule_sys_warn(
8957 p_text => GET_NOT_TRANSLATED_TEXT(
8958 CZ_FCE_SW_INVALID_ARG_PARAM,
8959 'EXPR_TYPE', t_exp_exprtype ( l_expr_index ),
8960 'ARG_LOCATION', 'fifth' ),
8961 p_warning_location => 'parse_template_application');
8962
8963 ELSIF ( t_exp_exprtype ( l_expr_index ) = h_exprtypes ('literal') AND t_exp_propertyid ( i ) IS NULL ) THEN
8964 -- 'Property is not defined. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
8965 report_and_raise_rule_sys_warn(
8966 p_text => GET_NOT_TRANSLATED_TEXT(
8967 CZ_FCE_SW_PROP_NOT_DEFINED),
8968 p_warning_location => 'parse_template_application');
8969
8970 END IF;
8971
8972 l_property_id := get_property_id ( l_expr_index );
8973 get_property_info ( l_property_id, l_data_type, l_def_value );
8974
8975 h_property_by_iterator ( 2 )( TO_CHAR ( l_property_id )) := 1;
8976 l_right_key := get_table_reference ( l_data_type, 2, 1 );
8977
8978 END CASE;
8979 END LOOP;
8980
8981 RETURN parse_operator ( l_left_key, l_operator, l_right_key );
8982 END parse_template_application;
8983 ----------------------------------------------------------------------------------
8984 -- Scope: generate_compatible
8985 FUNCTION parse_statement_compatible ( j IN PLS_INTEGER ) RETURN VARCHAR2 IS
8986
8987 l_index PLS_INTEGER;
8988 l_expr_index PLS_INTEGER;
8989 l_participant_index PLS_INTEGER;
8990 l_where_index PLS_INTEGER;
8991 l_count PLS_INTEGER;
8992
8993 l_if VARCHAR2(32000);
8994 l_expr_id VARCHAR2(4000);
8995
8996 BEGIN
8997
8998 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
8999
9000 IF ( expr_has_children ( l_expr_id )) THEN
9001
9002 l_index := h_exprid_childrenindex ( l_expr_id ) - 1;
9003
9004 ELSE
9005
9006 report_and_raise_rule_sys_warn (
9007 p_text => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SW_RE_ENODE_CHILDREN,
9008 'EXPR_ID', l_expr_id ),
9009 p_warning_location => 'parse_statement_compatible');
9010
9011 END IF;
9012
9013 l_where_index := 0;
9014
9015 --This is a COMPATIBLE rule. Find iterator definition indexes and WHERE clause index.
9016
9017 FOR i IN 1..h_exprid_numberofchildren ( l_expr_id ) LOOP
9018
9019 l_expr_index := l_index + i;
9020
9021 CASE t_exp_exprtype ( l_expr_index ) WHEN h_exprtypes ('iterator') THEN
9022
9023 l_count := h_index_by_iterator.COUNT + 1;
9024 h_index_by_iterator ( t_exp_argumentname ( l_expr_index )) := l_count;
9025
9026 --For A COMPATIBLE, a child of an iterator is always a participant.
9027
9028 IF ( expr_has_one_child ( TO_CHAR ( t_exp_exprnodeid ( l_expr_index )))) THEN
9029
9030 l_participant_index := h_exprid_childrenindex ( TO_CHAR ( t_exp_exprnodeid ( l_expr_index )));
9031
9032 ELSE
9033
9034 report_and_raise_rule_sys_warn(
9035 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_RE_ENODE_ONE_CHILD,
9036 'EXPR_ID', TO_CHAR ( t_exp_exprnodeid ( l_expr_index ))),
9037 p_warning_location => 'parse_where_clause');
9038
9039 END IF;
9040
9041 c_.participants ( l_count ).ps_node_id := t_exp_psnodeid ( l_participant_index );
9042 c_.participants ( l_count ).model_ref_expl_id := t_exp_modelrefexplid ( l_participant_index );
9043
9044 WHEN h_exprtypes ('where') THEN
9045
9046 IF ( expr_has_children ( TO_CHAR ( t_exp_exprnodeid ( l_expr_index )))) THEN
9047
9048 l_where_index := h_exprid_childrenindex ( TO_CHAR ( t_exp_exprnodeid ( l_expr_index )));
9049
9050 ELSE
9051
9052 report_and_raise_rule_sys_warn (
9053 p_text => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SW_RE_ENODE_CHILDREN,
9054 'EXPR_ID', TO_CHAR ( t_exp_exprnodeid ( l_expr_index ))),
9055 p_warning_location => 'parse_statement_compatible');
9056
9057 END IF;
9058
9059 ELSE
9060
9061 --#<should never happen>
9062 -- 'Invalid structure of a compatibility rule. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
9063 report_and_raise_rule_sys_warn(
9064 p_text => GET_NOT_TRANSLATED_TEXT(
9065 CZ_FCE_SW_INVALID_STRUCTURE),
9066 p_warning_location => 'parse_statement_compatible');
9067
9068 END CASE;
9069 END LOOP;
9070
9071 IF ( h_index_by_iterator.COUNT = 0 ) THEN
9072
9073 --#<should never happen>
9074 -- 'No iterator specified. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
9075 report_and_raise_rule_sys_warn(
9076 p_text => GET_NOT_TRANSLATED_TEXT(
9077 CZ_FCE_SW_NO_ITERATOR ),
9078 p_warning_location => 'parse_statement_compatible');
9079
9080 END IF;
9081
9082 IF ( l_where_index <> 0 ) THEN
9083
9084 l_if := parse_where_clause ( l_where_index, const_ruletype_compatible, h_index_by_iterator, h_property_by_iterator );
9085
9086 END IF;
9087 RETURN l_if;
9088
9089 END parse_statement_compatible;
9090 ----------------------------------------------------------------------------------
9091 BEGIN --> generate_compatible
9092
9093 c_.participants.DELETE;
9094 c_.combinations.DELETE;
9095
9096 o_.DELETE;
9097 n_.DELETE;
9098 s_.DELETE;
9099 t_.DELETE;
9100 b_.DELETE;
9101
9102 IF ( t_exp_exprtype ( j ) = h_exprtypes ('compatible')) THEN
9103
9104 l_parsed := parse_statement_compatible ( j );
9105
9106 ELSE
9107
9108 l_parsed := parse_template_application ( j );
9109
9110 END IF;
9111
9112 --Read all the property values and populate the arrays.
9113
9114 FOR i IN 1..c_.participants.COUNT LOOP
9115
9116 l_key := h_property_by_iterator ( i ).FIRST;
9117 t_children := explode_node_children ( c_.participants ( i ).ps_node_id, c_.participants ( i ).model_ref_expl_id, FALSE );
9118
9119 WHILE ( l_key IS NOT NULL ) LOOP
9120
9121 l_property_id := TO_NUMBER ( l_key );
9122
9123 get_property_info ( l_property_id, l_data_type, l_value );
9124 l_property_index := h_property_by_iterator ( i )( l_key );
9125
9126 FOR ii IN 1..t_children.COUNT LOOP
9127
9128 o_( i )( ii ).ps_node_id := t_children ( ii ).ps_node_id;
9129
9130 IF ( l_parsed IS NOT NULL ) THEN
9131
9132 --We need to actually get the property values and populate corresponding arrays only if there
9133 --is a WHERE clause. Probably, a compatibility rule without a WHERE clause should be reported.
9134
9135 l_value := get_property_value ( l_property_id, t_children ( ii ).ps_node_id, t_children ( ii ).model_ref_expl_id );
9136
9137 IF ( l_data_type IN ( h_datatypes ('integer'), h_datatypes ('decimal'))) THEN
9138
9139 n_( i )( ii )( l_property_index ) := TO_NUMBER ( l_value );
9140
9141 ELSIF ( l_data_type = h_datatypes ('boolean')) THEN
9142
9143 --We use integer representation of boolean as 0/1.
9144
9145 b_( i )( ii )( l_property_index ) := TO_NUMBER ( l_value );
9146
9147 ELSE
9148
9149 --For all other types (text and translatable) we use text.
9150
9151 t_( i )( ii )( l_property_index ) := l_value;
9152
9153 END IF;
9154 END IF;
9155 END LOOP;
9156
9157 s_( i ) := t_children.COUNT;
9158 l_key := h_property_by_iterator ( i ).NEXT ( l_key );
9159
9160 END LOOP;
9161 END LOOP;
9162
9163 --This will populate the table of combinations.
9164
9165 EXECUTE IMMEDIATE build_executable ( c_.participants.COUNT, l_parsed );
9166 verify_compatibility_table ( c_, FALSE );
9167
9168 --Now generate the compatibility table.
9169
9170 generate_compat_table ( c_, p_input_context, x_output_context );
9171 x_output_context.context_type := const_context_compatible;
9172
9173 END generate_compatible;
9174 ----------------------------------------------------------------------------------
9175 -- Scope: compile_constraints
9176 PROCEDURE generate_explicit_compat ( p_input_context IN expression_context
9177 , x_output_context IN OUT NOCOPY expression_context
9178 ) IS
9179
9180 tl_modelrefexplid type_number_table;
9181 tl_featureid type_number_table;
9182 tl_primaryoptid type_number_table;
9183 tl_secondaryoptid type_number_table;
9184
9185 l_compat_table type_compat_table;
9186 hl_features type_data_hashtable;
9187
9188 l_key VARCHAR2(4000);
9189 l_count PLS_INTEGER;
9190
9191 BEGIN
9192
9193 --We don't even need cz_des_chart_features table for explicit compatibility. Here we read all the data
9194 --in bulk and then transform it into another form in memory. This way we don't need any SQL ordering.
9195
9196 SELECT primary_opt_id, secondary_opt_id, secondary_feature_id, secondary_feat_expl_id
9197 BULK COLLECT INTO tl_primaryoptid, tl_secondaryoptid, tl_featureid, tl_modelrefexplid
9198 FROM cz_des_chart_cells
9199 WHERE deleted_flag = '0'
9200 AND rule_id = this_rule_id;
9201
9202 FOR i IN 1..tl_primaryoptid.COUNT LOOP
9203
9204 --We are using the same key as for storing context nodes in local variables because we will be
9205 --storing and loading nodes when generating compatibility table.
9206
9207 l_key := tl_featureid ( i ) || '-' || tl_modelrefexplid ( i );
9208
9209 IF ( NOT hl_features.EXISTS ( l_key )) THEN
9210
9211 l_count := l_compat_table.participants.COUNT + 1;
9212 hl_features ( l_key ) := l_count;
9213
9214 l_compat_table.participants ( l_count ).ps_node_id := tl_featureid ( i );
9215 l_compat_table.participants ( l_count ).model_ref_expl_id := tl_modelrefexplid ( i );
9216
9217 ELSE
9218
9219 l_count := hl_features ( l_key );
9220
9221 END IF;
9222
9223 l_compat_table.combinations ( tl_primaryoptid ( i ))( l_count ).ps_node_id := tl_secondaryoptid ( i );
9224
9225 END LOOP;
9226
9227 verify_compatibility_table ( l_compat_table, FALSE );
9228
9229 --Now generate the compatibility table.
9230
9231 generate_compat_table ( l_compat_table, p_input_context, x_output_context );
9232
9233 END generate_explicit_compat;
9234 ----------------------------------------------------------------------------------
9235 -- Scope: compile_constraints
9236 PROCEDURE generate_design_chart ( p_input_context IN expression_context
9237 , x_output_context IN OUT NOCOPY expression_context
9238 ) IS
9239
9240 tl_modelrefexplid type_number_table;
9241 tl_featureid type_number_table;
9242 tl_featuretype type_number_table;
9243 tl_primaryoptid type_number_table;
9244 tl_secondaryoptid type_number_table;
9245 tl_secondaryfeatid type_number_table;
9246 tl_secondaryfeatexplid type_number_table;
9247
9248 tl_primary type_iteratornode_table;
9249 tl_defining type_iteratornode_table;
9250 tl_optional type_iteratornode_table;
9251
9252 hl_combinations type_nodehashtable_hashtable;
9253 h_comb_number type_data_hashtable;
9254
9255 l_compat_tables type_compattable_table;
9256 l_count PLS_INTEGER;
9257 l_index PLS_INTEGER;
9258 l_compat_index PLS_INTEGER;
9259 l_combinations PLS_INTEGER;
9260
9261 l_key VARCHAR2(4000);
9262 l_primary_key VARCHAR2(4000);
9263
9264 BEGIN
9265
9266 SELECT feature_id, model_ref_expl_id, feature_type
9267 BULK COLLECT INTO tl_featureid, tl_modelrefexplid, tl_featuretype
9268 FROM cz_des_chart_features
9269 WHERE deleted_flag = '0'
9270 AND rule_id = this_rule_id;
9271
9272 IF ( tl_featureid.COUNT = 0 ) THEN
9273 -- Design chart is empty. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
9274 report_and_raise_rule_warning(
9275 p_text => CZ_UTILS.GET_TEXT(
9276 CZ_FCE_W_EMPTY_DESIGN_CHART,
9277 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
9278 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
9279 p_warning_location => 'generate_design_chart' );
9280
9281 END IF;
9282
9283 FOR i IN 1..tl_featureid.COUNT LOOP
9284
9285 IF ( tl_featuretype ( i ) = h_designtypes('primary')) THEN
9286
9287 l_count := tl_primary.COUNT + 1;
9288
9289 tl_primary ( l_count ).ps_node_id := tl_featureid ( i );
9290 tl_primary ( l_count ).model_ref_expl_id := tl_modelrefexplid ( i );
9291
9292 ELSIF ( tl_featuretype ( i ) = h_designtypes('defining')) THEN
9293
9294 l_count := tl_defining.COUNT + 1;
9295
9296 tl_defining ( l_count ).ps_node_id := tl_featureid ( i );
9297 tl_defining ( l_count ).model_ref_expl_id := tl_modelrefexplid ( i );
9298
9299 ELSIF ( tl_featuretype ( i ) = h_designtypes('optional')) THEN
9300
9301 l_count := tl_optional.COUNT + 1;
9302
9303 tl_optional ( l_count ).ps_node_id := tl_featureid ( i );
9304 tl_optional ( l_count ).model_ref_expl_id := tl_modelrefexplid ( i );
9305
9306 ELSE
9307 -- 'Found invalid feature type "^FEAT_TYPE". Design Chart Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
9308 report_and_raise_rule_sys_warn(
9309 p_text => GET_NOT_TRANSLATED_TEXT(
9310 CZ_FCE_SW_INVAL_FEAT_TYPE_DC,
9311 'FEAT_TYPE', tl_featuretype ( i )
9312 ),
9313 p_warning_location => 'generate_design_chart' );
9314
9315 END IF;
9316 END LOOP;
9317
9318 IF ( tl_primary.COUNT <> 1 ) THEN
9319 -- The primary feature in the design chart is either missing or duplicated. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
9320 report_and_raise_rule_warning(
9321 p_text => CZ_UTILS.GET_TEXT(
9322 CZ_FCE_W_NO_PRIMARY_FEAT_DC,
9323 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
9324 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path)),
9325 p_warning_location => 'generate_design_chart' );
9326
9327 END IF;
9328
9329 IF ( tl_defining.COUNT = 0 AND tl_optional.COUNT = 0) THEN
9330
9331 report_and_raise_rule_warning(
9332 p_text => CZ_UTILS.GET_TEXT(
9333 CZ_FCE_W_EMPTY_DESIGN_CHART,
9334 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
9335 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
9336 p_warning_location => 'generate_design_chart' );
9337
9338 END IF;
9339
9340 SELECT primary_opt_id, secondary_opt_id, secondary_feature_id, secondary_feat_expl_id
9341 BULK COLLECT INTO tl_primaryoptid, tl_secondaryoptid, tl_secondaryfeatid, tl_secondaryfeatexplid
9342 FROM cz_des_chart_cells
9343 WHERE deleted_flag = '0'
9344 AND rule_id = this_rule_id;
9345
9346 FOR i IN 1..tl_primaryoptid.COUNT LOOP
9347
9348 l_key := TO_CHAR ( tl_secondaryfeatid ( i )) || '-' || TO_CHAR ( tl_secondaryfeatexplid ( i ));
9349 hl_combinations ( l_key )( i ) := tl_secondaryoptid ( i );
9350
9351 END LOOP;
9352
9353 l_compat_index := 1;
9354
9355 IF ( tl_defining.COUNT > 0 ) THEN
9356
9357 --Build and verify the defining compatibility table.
9358
9359 l_compat_tables ( l_compat_index ).participants ( 1 ) := tl_primary ( 1 );
9360
9361 FOR i IN 1..tl_defining.COUNT LOOP
9362
9363 l_compat_tables ( l_compat_index ).participants ( i + 1 ) := tl_defining ( i );
9364 l_key := TO_CHAR ( tl_defining ( i ).ps_node_id ) || '-' || TO_CHAR ( tl_defining ( i ).model_ref_expl_id );
9365
9366 IF ( NOT hl_combinations.EXISTS ( l_key )) THEN
9367 -- No selection made between primary and defining feature in design chart rule. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
9368 report_and_raise_rule_warning(
9369 p_text => CZ_UTILS.GET_TEXT(
9370 CZ_FCE_W_NO_COMBINATIONS_DC,
9371 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
9372 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
9373 p_warning_location => 'generate_design_chart' );
9374
9375 END IF;
9376
9377 IF ( i = 1 ) THEN
9378
9379 l_combinations := hl_combinations ( l_key ).COUNT;
9380
9381 ELSE
9382
9383 IF ( hl_combinations ( l_key ).COUNT <> l_combinations ) THEN
9384 -- No one-to-one correspondence between options of primary and defining feature in design chart rule. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
9385 report_and_raise_rule_warning(
9386 p_text => CZ_UTILS.GET_TEXT(
9387 CZ_FCE_W_INVALID_NUM_COMB_DC,
9388 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
9389 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
9390 p_warning_location => 'generate_design_chart' );
9391
9392 END IF;
9393 END IF;
9394
9395 l_index := hl_combinations ( l_key ).FIRST;
9396
9397 IF ( i = 1 ) THEN
9398
9399 --As part of the processing for the first defining feature, we will populate the first position
9400 --of each combination with corresponding primary option id, and establish a map between primary
9401 --options and combinations. This map will be used to retrieve the combination number by primary
9402 --option for other defining features.
9403
9404 l_count := 1;
9405
9406 WHILE ( l_index IS NOT NULL ) LOOP
9407
9408 l_compat_tables ( l_compat_index ).combinations ( l_count )( 1 ).ps_node_id := tl_primaryoptid ( l_index );
9409 l_compat_tables ( l_compat_index ).combinations ( l_count )( 2 ).ps_node_id := hl_combinations ( l_key )( l_index );
9410
9411 --Bug #7519498 - we cannot assume the same order of primary options within each combination
9412 --because the sql statement does not use any ordering. So, we need to build a map between
9413 --primary option id(s) and combination numbers.
9414
9415 h_comb_number ( TO_CHAR ( tl_primaryoptid ( l_index ))) := l_count;
9416
9417 l_index := hl_combinations ( l_key ).NEXT ( l_index );
9418 l_count := l_count + 1;
9419
9420 END LOOP;
9421
9422 ELSE
9423
9424 WHILE ( l_index IS NOT NULL ) LOOP
9425
9426 l_count := h_comb_number ( TO_CHAR ( tl_primaryoptid ( l_index )));
9427 l_compat_tables ( l_compat_index ).combinations ( l_count )( i + 1 ).ps_node_id := hl_combinations ( l_key )( l_index );
9428
9429 l_index := hl_combinations ( l_key ).NEXT ( l_index );
9430
9431 END LOOP;
9432 END IF;
9433 END LOOP;
9434
9435 verify_compatibility_table ( l_compat_tables ( l_compat_index ), FALSE );
9436 l_compat_index := l_compat_index + 1;
9437
9438 END IF; --build defining compatibility table
9439
9440 --Build all the optional compatibility tables.
9441
9442 FOR i IN 1..tl_optional.COUNT LOOP
9443
9444 l_compat_tables ( l_compat_index ).participants ( 1 ) := tl_primary ( 1 );
9445 l_compat_tables ( l_compat_index ).participants ( 2 ) := tl_optional ( i );
9446
9447 l_key := TO_CHAR ( tl_optional ( i ).ps_node_id ) || '-' || TO_CHAR ( tl_optional ( i ).model_ref_expl_id );
9448
9449 --For the optional feature there can be no combinations. In this case generate_compat_table
9450 --will generate and exclude relation between the primary and the optional features.
9451
9452 IF ( hl_combinations.EXISTS ( l_key )) THEN
9453
9454 l_index := hl_combinations ( l_key ).FIRST;
9455 l_count := 1;
9456
9457 WHILE ( l_index IS NOT NULL ) LOOP
9458
9459 l_compat_tables ( l_compat_index ).combinations ( l_count )( 2 ).ps_node_id := hl_combinations ( l_key )( l_index );
9460 l_compat_tables ( l_compat_index ).combinations ( l_count )( 1 ).ps_node_id := tl_primaryoptid ( l_index );
9461
9462 l_index := hl_combinations ( l_key ).NEXT ( l_index );
9463 l_count := l_count + 1;
9464
9465 END LOOP;
9466 END IF;
9467
9468 verify_compatibility_table ( l_compat_tables ( l_compat_index ), TRUE );
9469 l_compat_index := l_compat_index + 1;
9470
9471 END LOOP;
9472
9473 --Generate all the compatibility tables.
9474
9475 FOR i IN 1..l_compat_tables.COUNT LOOP
9476
9477 generate_compat_table ( l_compat_tables ( i ), p_input_context, x_output_context );
9478
9479 END LOOP;
9480 END generate_design_chart;
9481 ----------------------------------------------------------------------------------
9482 -- Scope: compile_constraints
9483 PROCEDURE generate_power ( j IN PLS_INTEGER
9484 , p_input_context IN expression_context
9485 , x_output_context IN OUT NOCOPY expression_context
9486 ) IS
9487
9488 l_expr_id VARCHAR2(4000);
9489 l_index PLS_INTEGER;
9490 l_aux PLS_INTEGER;
9491
9492 BEGIN
9493
9494 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
9495
9496 IF ( expr_has_two_children ( l_expr_id )) THEN
9497
9498 l_index := h_exprid_childrenindex ( l_expr_id );
9499
9500 ELSE
9501
9502 -- 'Incomplete power operator. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
9503 report_and_raise_rule_sys_warn(
9504 p_text => GET_NOT_TRANSLATED_TEXT(
9505 CZ_FCE_SW_INCOMPLETE_POWER ),
9506 p_warning_location => 'generate_power');
9507
9508 END IF;
9509
9510 l_aux := l_index + 1;
9511
9512 IF ( t_exp_exprtype ( l_aux ) <> h_exprtypes ('literal') OR t_exp_datatype ( l_aux ) <> h_datatypes ('integer')) THEN
9513 -- 'The exponent of the power operaror must be an integer constant. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
9514 report_and_raise_rule_sys_warn(
9515 p_text => GET_NOT_TRANSLATED_TEXT(
9516 CZ_FCE_SW_EXP_PWR_MUST_BE_INT ),
9517 p_warning_location => 'generate_power' );
9518
9519 END IF;
9520
9521 generate_expression ( l_index, p_input_context, x_output_context );
9522 generate_expression ( l_aux, p_input_context, x_output_context );
9523
9524 emit_invokevirtual ('INumExprDef.pow(int)');
9525
9526 END generate_power;
9527 ----------------------------------------------------------------------------------
9528 -- Scope: compile_constraints
9529 PROCEDURE generate_mathrounding ( j IN PLS_INTEGER
9530 , p_input_context IN expression_context
9531 , x_output_context IN OUT NOCOPY expression_context
9532 ) IS
9533
9534 l_expr_id VARCHAR2(4000);
9535 l_index PLS_INTEGER;
9536 l_aux PLS_INTEGER;
9537
9538 l_template_id NUMBER := t_exp_templateid ( j );
9539
9540 BEGIN
9541
9542 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
9543
9544 IF ( expr_has_two_children ( l_expr_id )) THEN
9545
9546 l_index := h_exprid_childrenindex ( l_expr_id );
9547
9548 ELSE
9549
9550 -- 'Incomplete math rounding operator. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
9551
9552 report_and_raise_rule_sys_warn(
9553 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_INCOMPLETE_MROUND ),
9554 p_warning_location => 'generate_mathrounding');
9555
9556 END IF;
9557
9558 l_aux := l_index + 1;
9559
9560 generate_expression ( l_index, p_input_context, x_output_context );
9561
9562 IF ( l_template_id = h_templates ('mod')) THEN
9563
9564 emit_dup ();
9565
9566 END IF;
9567
9568 generate_expression ( l_aux, p_input_context, x_output_context );
9569 copyto_local_variable ('var');
9570
9571 invoke_operator2 ( h_templates ('div'), l_aux, x_output_context );
9572 emit_invokevirtual ( h_mathrounding_ops ( l_template_id ));
9573
9574 aload_local_variable ('var');
9575 invoke_operator2 ( h_templates ('multiply'), l_aux, x_output_context );
9576
9577 IF ( l_template_id = h_templates ('mod')) THEN
9578
9579 emit_invokevirtual ('INumExprDef.diff(INumExprDef)');
9580
9581 END IF;
9582 END generate_mathrounding;
9583 ----------------------------------------------------------------------------------
9584 PROCEDURE generate_trigonometric ( j IN PLS_INTEGER
9585 , p_input_context IN expression_context
9586 , x_output_context IN OUT NOCOPY expression_context
9587 ) IS
9588
9589 l_expr_id VARCHAR2(4000);
9590 l_index PLS_INTEGER;
9591
9592 l_template_id NUMBER := t_exp_templateid ( j );
9593
9594 BEGIN
9595
9596 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
9597
9598 IF ( expr_has_one_child ( l_expr_id )) THEN
9599
9600 l_index := h_exprid_childrenindex ( l_expr_id );
9601
9602 ELSE
9603
9604 -- 'Incomplete math trigonometric operator. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
9605
9606 report_and_raise_rule_sys_warn(
9607 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_INCOMPLETE_TRIG ),
9608 p_warning_location => 'generate_trigonometric');
9609
9610 END IF;
9611
9612 generate_expression ( l_index, p_input_context, x_output_context );
9613
9614 IF ( l_template_id = h_templates ('log')) THEN
9615
9616 --<log> ::= x.log().div(Solver.literal(10).log())
9617
9618 emit_invokevirtual ('INumExprDef.log()');
9619
9620 aload_model_def ( p_component_id );
9621
9622 emit_code ( h_inst ('bipush') || cz_fce_compile_utils.byte ( 10 ));
9623 emit_invokevirtual('IModelDef.literal(int)');
9624
9625 emit_invokevirtual ('INumExprDef.log()');
9626 emit_invokevirtual ('INumExprDef.div(INumExprDef)');
9627
9628 ELSIF ( l_template_id IN ( h_templates ('cosh'), h_templates ('sinh'))) THEN
9629
9630 --<cosh> ::= (x.exp().sum(x.neg().exp())).div(2)
9631 --<sinh> ::= (x.exp().diff(x.neg().exp())).div(2)
9632
9633 copyto_local_variable ('var');
9634 emit_invokevirtual ('INumExprDef.exp()');
9635
9636 aload_local_variable ('var');
9637 emit_invokevirtual ('INumExprDef.neg()');
9638 emit_invokevirtual ('INumExprDef.exp()');
9639
9640 emit_invokevirtual ('INumExprDef.' || CASE l_template_id WHEN h_templates ('cosh') THEN 'sum' ELSE 'diff' END || '(INumExprDef)');
9641 emit_code ( h_inst ('iconst_2'));
9642 emit_invokevirtual ('INumExprDef.div(int)');
9643
9644 ELSIF ( l_template_id IN ( h_templates ('sin'), h_templates ('tan'))) THEN
9645
9646 --<sin> ::= (x.diff(Solver.literal(Math.PI).div(2))).cos()
9647 --<tan> ::= ((x.diff(Solver.literal(Math.PI).div(2))).cos()).div(x.cos())
9648
9649 IF ( l_template_id = h_templates ('tan')) THEN
9650
9651 copyto_local_variable ('var');
9652
9653 END IF;
9654
9655 aload_model_def ( p_component_id );
9656 emit_constant ( h_mathconstants ('pi'));
9657 emit_invokevirtual('IModelDef.literal(double)');
9658
9659 emit_code ( h_inst ('iconst_2'));
9660 emit_invokevirtual ('INumExprDef.div(int)');
9661
9662 emit_invokevirtual ('INumExprDef.diff(INumExprDef)');
9663 emit_invokevirtual ('INumExprDef.cos()');
9664
9665 IF ( l_template_id = h_templates ('tan')) THEN
9666
9667 aload_local_variable ('var');
9668 emit_invokevirtual ('INumExprDef.cos()');
9669 emit_invokevirtual ('INumExprDef.div(INumExprDef)');
9670
9671 END IF;
9672
9673 ELSIF ( l_template_id = h_templates ('tanh')) THEN
9674
9675 --<tanh> ::= (((x.prod(2)).exp()).diff(1)).div((((x.prod(2)).exp())).sum(1))
9676
9677 emit_code ( h_inst ('iconst_2'));
9678 emit_invokevirtual ('INumExprDef.prod(int)');
9679 emit_invokevirtual ('INumExprDef.exp()');
9680
9681 copyto_local_variable ('var');
9682 emit_code ( h_inst ('iconst_1'));
9683 emit_invokevirtual ('INumExprDef.diff(int)');
9684
9685 aload_local_variable ('var');
9686 emit_code ( h_inst ('iconst_1'));
9687 emit_invokevirtual ('INumExprDef.sum(int)');
9688
9689 emit_invokevirtual ('INumExprDef.div(INumExprDef)');
9690
9691 ELSE
9692 -- 'Mathematical operator is not implemented for template_id "^TEMPL_ID". Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
9693 report_and_raise_rule_sys_warn(
9694 p_text => GET_NOT_TRANSLATED_TEXT(
9695 CZ_FCE_SW__NO_MATH_OP,
9696 'TEMPL_ID', l_template_id ),
9697 p_warning_location => 'generate_trigonometric' );
9698
9699 END IF;
9700 END generate_trigonometric;
9701 ----------------------------------------------------------------------------------
9702 PROCEDURE generate_heuristics ( j IN PLS_INTEGER
9703 , p_input_context IN expression_context
9704 , x_output_context IN OUT NOCOPY expression_context
9705 ) IS
9706
9707 l_expr_id VARCHAR2(4000);
9708 l_method VARCHAR2(4000);
9709 l_key VARCHAR2(4000);
9710
9711 l_index PLS_INTEGER;
9712 l_node_id NUMBER;
9713 l_property_id NUMBER;
9714
9715 l_parameter type_iterator_value;
9716
9717 BEGIN
9718
9719 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
9720
9721 IF ( expr_has_one_child ( l_expr_id )) THEN
9722
9723 l_index := h_exprid_childrenindex ( l_expr_id );
9724
9725 ELSE
9726
9727 -- 'Incomplete Default or Search Decision. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
9728 report_and_raise_rule_sys_warn(
9729 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_INCOMPLETE_SEARCH ),
9730 p_warning_location => 'generate_heuristics');
9731
9732 END IF;
9733
9734 -- 'Invalid default or search decision is found. Here operand can only be a structure node. Rule "^RULE_NAME" in the model "^MODEL_NAME" ignored.';
9735
9736 l_parameter := get_structure_node ( l_index );
9737
9738 IF ( l_parameter.value_type IS NULL ) THEN
9739
9740 report_and_raise_rule_sys_warn(
9741 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_SD_OPAND_STRUCT_N ),
9742 p_warning_location => 'generate_heuristics');
9743
9744 END IF;
9745
9746 l_node_id := l_parameter.ps_node_id;
9747 l_key := TO_CHAR ( l_node_id );
9748
9749 IF ( h_psnid_devlprojectid ( l_key ) <> p_component_id ) THEN
9750
9751 -- Defaults and search decisions cannot be defined across different models. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
9752
9753 report_and_raise_rule_warning(
9754 p_text => CZ_UTILS.GET_TEXT(
9755 CZ_FCE_W_SD_NOT_ACROSS_MODELS,
9756 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
9757 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path)),
9758 p_warning_location => 'generate_heuristics');
9759
9760 END IF;
9761
9762 --Load the model def, in which the constraint will be defined, and the variable.
9763
9764 aload_model_def ( h_psnid_parentid ( l_key ));
9765 haload_object ( l_node_id, 1 );
9766
9767 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( l_index ));
9768
9769 IF ( NOT h_exprid_childrenindex.EXISTS ( l_expr_id )) THEN
9770
9771 --No property is specified, need to default in some cases.
9772
9773 IF ( is_bom_node ( h_psnid_backindex ( l_key ))) THEN
9774
9775 l_property_id := h_templates ('quantity');
9776
9777 ELSIF ( t_exp_templateid ( j ) <> h_templates ('assign')) THEN
9778
9779 --We don't need to default property for assign operator except for bom.
9780
9781 IF ( h_psnid_detailedtype ( l_key ) IN ( h_psntypes ('component'), h_psntypes ('reference'), h_psntypes ('connector'))) THEN
9782
9783 l_property_id := h_templates('instancecount');
9784
9785 ELSIF ( h_psnid_detailedtype ( l_key ) = h_psntypes ('optionfeature')) THEN
9786
9787 l_property_id := h_templates ('quantity');
9788
9789 END IF;
9790 END IF;
9791 ELSE
9792
9793 l_property_id := get_property_id ( h_exprid_childrenindex ( l_expr_id ));
9794
9795 END IF;
9796
9797 IF ( l_property_id IS NOT NULL ) THEN
9798
9799 apply_system_property ( l_property_id, h_psnid_backindex ( l_key ), p_input_context );
9800
9801 END IF;
9802
9803 emit_invokevirtual ( h_heuristic_ops ( t_exp_templateid ( j )));
9804 emit_effectivity ( 'IDecisionDef', this_effective_from, this_effective_until, this_effective_usages );
9805
9806 IF ( this_rule_class = h_ruleclasses ('default')) THEN
9807
9808 emit_invokevirtual ('IModelDef.addDefaultDecision(IDecisionExprDef)');
9809
9810 ELSIF ( this_rule_class = h_ruleclasses ('search')) THEN
9811
9812 emit_invokevirtual ('IModelDef.addSearchDecision(IDecisionExprDef)');
9813
9814 ELSE
9815 -- Heuristic operators (IncMin, DecMax, Assign, MinFirst, MaxFirst) can only be used in defaults or search decisions. Rule ^RULE_NAME in model ^MODEL_NAME ignored.
9816 report_and_raise_rule_warning(
9817 p_text => CZ_UTILS.GET_TEXT(
9818 CZ_FCE_W_HEUR_ONLY_IN_DEF,
9819 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
9820 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
9821 p_warning_location => 'generate_heuristics' );
9822
9823 END IF;
9824
9825 emit_pop ( 1 );
9826 x_output_context.context_type := const_context_heuristics;
9827
9828 END generate_heuristics;
9829 ----------------------------------------------------------------------------------
9830 -- Scope: compile_constraints
9831 PROCEDURE generate_aggregatesum ( j IN PLS_INTEGER
9832 , p_input_context IN expression_context
9833 , x_output_context IN OUT NOCOPY expression_context
9834 ) IS
9835
9836 l_expr_id VARCHAR2(4000);
9837 l_index PLS_INTEGER;
9838 l_return PLS_INTEGER := const_no_instances;
9839
9840 l_input_context expression_context := p_input_context;
9841 l_output_context expression_context;
9842
9843 l_parameter type_iterator_value;
9844
9845 BEGIN
9846
9847 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
9848
9849 IF ( expr_has_one_child ( l_expr_id )) THEN
9850
9851 l_index := h_exprid_childrenindex ( l_expr_id );
9852
9853 ELSE
9854
9855 report_and_raise_rule_sys_warn(
9856 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_INCOMPLETE_AGSUM ),
9857 p_warning_location => 'generate_aggregatesum');
9858
9859 END IF;
9860
9861 l_parameter := get_structure_node ( l_index );
9862
9863 IF ( l_parameter.value_type IS NULL ) THEN
9864
9865 report_and_raise_rule_sys_warn(
9866 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_AS_OPAND_STRUCT_N ),
9867 p_warning_location => 'generate_aggregatesum');
9868
9869 END IF;
9870
9871 l_input_context.context_type := const_context_aggregatesum;
9872 /*
9873 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( l_index ));
9874
9875 IF ( h_exprid_childrenindex.EXISTS ( l_expr_id ) AND t_exp_exprtype ( h_exprid_childrenindex ( l_expr_id ) ) = h_exprtypes ('property')) THEN
9876
9877 --User property is a special case - we need to generate the node, then push the
9878 --property value as an expression, and then call sum if necessary.
9879
9880 l_return := generate_path ( l_parameter.ps_node_id, l_parameter.model_ref_expl_id, l_input_context, x_output_context );
9881
9882 END IF;
9883 */
9884 generate_expression ( l_index, l_input_context, l_output_context );
9885
9886 IF ( l_return = const_resourcesum_required ) THEN
9887
9888 emit_invokevirtual('IPortExprDef.sum(INumExprDef)');
9889
9890 END IF;
9891 END generate_aggregatesum;
9892 ----------------------------------------------------------------------------------
9893 -- Scope: compile_constraints
9894 FUNCTION is_operator ( j IN PLS_INTEGER, p_operator IN VARCHAR2 ) RETURN BOOLEAN IS
9895 BEGIN
9896
9897 RETURN t_exp_exprtype ( j ) = h_exprtypes ('operator') AND t_exp_templateid ( j ) = h_templates ( p_operator );
9898
9899 END is_operator;
9900 ----------------------------------------------------------------------------------
9901 -- Scope: compile_constraints
9902 FUNCTION is_text_selection ( j IN PLS_INTEGER ) RETURN BOOLEAN IS
9903
9904 l_expr_id VARCHAR2(4000);
9905 l_index PLS_INTEGER;
9906
9907 BEGIN
9908
9909 IF ( t_exp_exprtype ( j ) = h_exprtypes ('argument')) THEN
9910
9911 RETURN retrieve_parameter ( t_exp_argumentname ( j )).value_type = const_valuetype_selection;
9912
9913 ELSE
9914
9915 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
9916
9917 IF (( NOT h_exprid_childrenindex.EXISTS ( l_expr_id )) OR h_exprid_numberofchildren ( l_expr_id ) = 1 ) THEN RETURN FALSE; END IF;
9918
9919 l_index := h_exprid_childrenindex ( l_expr_id );
9920 IF ( NVL ( t_exp_templateid ( l_index ), 0 ) = h_templates ('selection')) THEN RETURN TRUE; END IF;
9921
9922 END IF;
9923
9924 RETURN FALSE;
9925 END is_text_selection;
9926 ----------------------------------------------------------------------------------
9927 -- Scope: compile_constraints
9928 PROCEDURE generate_expression ( j IN PLS_INTEGER
9929 , p_input_context IN expression_context
9930 , x_output_context IN OUT NOCOPY expression_context
9931 ) IS
9932
9933 --Must be local variables because of recursion.
9934
9935 l_expr_id VARCHAR2(4000);
9936 l_index PLS_INTEGER;
9937 l_aux PLS_INTEGER;
9938 l_count PLS_INTEGER;
9939 l_key VARCHAR2(4000);
9940
9941 l_input_context expression_context := p_input_context;
9942 l_output_context expression_context;
9943
9944 l_left_context expression_context;
9945 l_right_context expression_context;
9946 l_acc_init type_varchar4000_table;
9947
9948 l_lhs_selection BOOLEAN;
9949 l_rhs_selection BOOLEAN;
9950 l_side PLS_INTEGER;
9951
9952 l_lhs_target NUMBER;
9953 l_rhs_target NUMBER;
9954
9955 BEGIN
9956
9957 CASE t_exp_exprtype ( j )
9958
9959 WHEN h_exprtypes ('node') THEN
9960
9961 generate_structure_node ( j, p_input_context, x_output_context );
9962
9963 WHEN h_exprtypes ('literal') THEN
9964
9965 generate_literal ( j, get_literal_value ( j ), t_exp_datatype ( j ), p_input_context, x_output_context );
9966
9967 WHEN h_exprtypes ('argument') THEN
9968
9969 generate_parameter ( j, p_input_context, x_output_context );
9970
9971 WHEN h_exprtypes ('operator') THEN
9972
9973 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
9974
9975 IF ( l_input_context.context_type = const_context_generic ) THEN
9976
9977 IF ( h_logical_ops.EXISTS ( t_exp_templateid ( j ))) THEN
9978
9979 l_input_context.context_type := const_context_logical;
9980
9981 ELSIF ( h_numeric_ops.EXISTS ( t_exp_templateid ( j ))) THEN
9982
9983 l_input_context.context_type := const_context_numeric;
9984
9985 END IF;
9986 END IF;
9987
9988 IF ( h_operators_2.EXISTS ( t_exp_templateid ( j ))) THEN
9989
9990 --Operators with 2 operands.
9991
9992 IF ( expr_has_two_children ( l_expr_id )) THEN
9993
9994 l_index := h_exprid_childrenindex ( l_expr_id );
9995
9996 ELSE
9997
9998 report_and_raise_rule_sys_warn(
9999 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_RE_ENODE_TWO_CHILD,
10000 'EXPR_ID', l_expr_id ),
10001 p_warning_location => 'generate_expression');
10002
10003 END IF;
10004
10005 l_aux := l_index + 1;
10006
10007 IF ( t_exp_templateid ( j ) IN ( h_templates ('subsetof'), h_templates ('union'))) THEN
10008
10009 --Special validation for SubsetOf and Union operators.
10010
10011 l_lhs_target := 0;
10012 l_rhs_target := 0;
10013
10014 IF ( t_exp_exprtype ( l_index ) = h_exprtypes ('node')) THEN
10015
10016 l_lhs_target := get_port_id ( TO_CHAR ( t_exp_psnodeid ( l_index )));
10017
10018 IF ( l_lhs_target IS NULL ) THEN
10019
10020 report_and_raise_rule_sys_warn (
10021 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_AS_PORT_LIMITS ),
10022 p_warning_location => 'generate_expression');
10023
10024 END IF;
10025 END IF;
10026
10027 IF ( t_exp_exprtype ( l_aux ) = h_exprtypes ('node')) THEN
10028
10029 l_rhs_target := get_port_id ( TO_CHAR ( t_exp_psnodeid ( l_aux )));
10030
10031 IF ( l_rhs_target IS NULL ) THEN
10032
10033 report_and_raise_rule_sys_warn (
10034 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_AS_PORT_LIMITS ),
10035 p_warning_location => 'generate_expression');
10036
10037 END IF;
10038 END IF;
10039
10040 IF ( l_lhs_target <> 0 AND l_rhs_target <> 0 AND l_lhs_target <> l_rhs_target ) THEN
10041
10042 report_and_raise_rule_sys_warn(
10043 p_text => GET_NOT_TRANSLATED_TEXT(
10044 CZ_FCE_SW_COMPARE_TXPROP_TXLIT ),
10045 p_warning_location => 'generate_expression' );
10046
10047 END IF;
10048 END IF;
10049
10050 generate_expression ( l_index, p_input_context, l_left_context );
10051 generate_expression ( l_aux, p_input_context, l_right_context );
10052
10053 --The following line corresponds to the case of division or multiplication by 1.
10054
10055 IF ( l_left_context.context_type = const_context_literal OR l_right_context.context_type = const_context_literal ) THEN RETURN; END IF;
10056
10057 invoke_operator2 ( t_exp_templateid ( j ), l_aux, l_right_context );
10058
10059 ELSIF ( h_operators_3.EXISTS ( t_exp_templateid ( j ))) THEN
10060
10061 --n-ary operators, defined on IModelDef: AnyTrue, AllTrue, Min, Max.
10062
10063 IF ( expr_has_children ( l_expr_id )) THEN
10064
10065 l_index := h_exprid_childrenindex ( l_expr_id );
10066
10067 ELSE
10068
10069 report_and_raise_rule_sys_warn (
10070 p_text => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SW_RE_ENODE_CHILDREN,
10071 'EXPR_ID', l_expr_id ),
10072 p_warning_location => 'generate_expression');
10073
10074 END IF;
10075
10076 l_aux := h_exprid_numberofchildren ( l_expr_id );
10077
10078 --Put all the operand expressions on the stack.
10079
10080 FOR i IN 1..l_aux LOOP
10081
10082 generate_expression ( l_index, l_input_context, x_output_context );
10083 l_index := l_index + 1;
10084
10085 END LOOP;
10086
10087 IF ( t_exp_templateid ( j ) IN ( h_templates ('anytrue'), h_templates ('alltrue'))) THEN
10088
10089 invoke_anyalltrue ( t_exp_templateid ( j ), h_exprid_numberofchildren ( l_expr_id ), t_exp_exprparentid ( j ));
10090
10091 ELSIF ( h_exprid_numberofchildren ( l_expr_id ) > 1 ) THEN
10092
10093 invoke_operator3 ( t_exp_templateid ( j ), h_exprid_numberofchildren ( l_expr_id ), 'INumExprDef' );
10094
10095 END IF;
10096
10097 --The number of children may have been changed by a collect, need to restore.
10098
10099 h_exprid_numberofchildren ( l_expr_id ) := l_aux;
10100
10101 ELSIF ( h_operators_1.EXISTS ( t_exp_templateid ( j ))) THEN
10102
10103 --Operators with 1 operand.
10104
10105 IF ( expr_has_one_child ( l_expr_id )) THEN
10106
10107 generate_expression ( h_exprid_childrenindex ( l_expr_id ), p_input_context, x_output_context );
10108
10109 ELSE
10110
10111 -- 'The expression node with the id-^EXPR_ID must have exactly one child. Rule ^RULE_NAME in the model ^MODEL_NAME ignored.'
10112
10113 report_and_raise_rule_sys_warn(
10114 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_RE_ENODE_ONE_CHILD,
10115 'EXPR_ID', l_expr_id ),
10116 p_warning_location => 'generate_expression');
10117
10118 END IF;
10119
10120 emit_invokevirtual ( h_operators_1 ( t_exp_templateid ( j )));
10121
10122 ELSIF ( t_exp_templateid ( j ) = h_templates('optionsof')) THEN
10123
10124 IF ( expr_has_one_child ( l_expr_id )) THEN
10125
10126 l_index := h_exprid_childrenindex ( l_expr_id );
10127
10128 ELSE
10129
10130 -- 'The expression node with the id-^EXPR_ID must have exactly one child. Rule ^RULE_NAME in the model ^MODEL_NAME ignored.'
10131
10132 report_and_raise_rule_sys_warn(
10133 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_RE_ENODE_ONE_CHILD,
10134 'EXPR_ID', l_expr_id ),
10135 p_warning_location => 'generate_expression');
10136
10137 END IF;
10138
10139 IF ( logical_context ( j, p_input_context.context_type )) THEN
10140
10141 --This is operator OptionsOf as a child of AnyTrue/AllTrue. Emulate property Options(),
10142 --applied to the operand.
10143
10144 t_exp_exprparentid ( l_index ) := t_exp_exprparentid ( j );
10145 generate_options ( l_index, p_input_context, x_output_context );
10146
10147 END IF;
10148
10149 ELSIF ( t_exp_templateid ( j ) = h_templates ('aggregatesum')) THEN
10150
10151 generate_aggregatesum ( j, p_input_context, x_output_context );
10152
10153 ELSIF ( t_exp_templateid ( j ) = h_templates ('logic')) THEN
10154
10155 generate_logic_template ( j, p_input_context, x_output_context );
10156
10157 ELSIF ( t_exp_templateid ( j ) = h_templates ('comparison')) THEN
10158
10159 generate_comparison_template ( j, p_input_context, x_output_context );
10160
10161 ELSIF ( t_exp_templateid ( j ) = h_templates ('accumulator')) THEN
10162
10163 generate_accumulator_template ( j, p_input_context, x_output_context );
10164
10165 ELSIF ( t_exp_templateid ( j ) = h_templates ('propertybased')) THEN
10166
10167 generate_compatible ( j, p_input_context, x_output_context );
10168
10169 ELSIF ( t_exp_templateid ( j ) IN ( h_templates ('addsto'), h_templates ('subtractsfrom'))) THEN
10170
10171 --This is an Accumulator rule.
10172
10173 l_expr_id := TO_CHAR ( t_exp_exprnodeid ( j ));
10174
10175 --Accumulator operator can only have two arguments.
10176
10177 IF ( expr_has_two_children ( l_expr_id )) THEN
10178
10179 l_index := h_exprid_childrenindex ( l_expr_id );
10180
10181 ELSE
10182
10183 report_and_raise_rule_sys_warn (
10184 p_text => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SW_RE_ENODE_TWO_CHILD,
10185 'EXPR_ID', l_expr_id ),
10186 p_warning_location => 'generate_expression');
10187
10188 END IF;
10189
10190 --This is expression index of the target.
10191
10192 --Need to generate the target first, because generation of contributor will depend on the
10193 --target (LCA). Cannot just generate the path here because target can be an argument, for
10194 --example, in case of FORALL operator.
10195
10196 l_aux := l_index + 1;
10197 l_input_context.context_type := const_context_target;
10198
10199 generate_expression ( l_aux, l_input_context, x_output_context );
10200
10201 l_count := x_output_context.context_num_data;
10202 l_key := x_output_context.context_data;
10203
10204 --If output context is 'target', the target didn't exist and needs to be stored.
10205 --For an existing target, the context would have been changed to 'generic' in
10206 --generate_path procedure.
10207
10208 IF ( x_output_context.context_type = const_context_target ) THEN
10209
10210 astore_register ( l_key );
10211
10212 t_target_quantifiers ( l_count ) := t_acc_quantifiers ( l_count );
10213 h_target_quantifiers ( l_count ) := h_acc_quantifiers ( l_count );
10214
10215 END IF;
10216
10217 l_input_context.context_type := const_context_contributor;
10218 l_input_context.context_num_data := l_count;
10219
10220 t_acc_local_quantifiers.DELETE;
10221 contributor_validation := 0;
10222
10223 generate_expression ( l_index, l_input_context, x_output_context );
10224
10225 IF ( contributor_validation > 1 ) THEN
10226
10227 --The output context contains the number of the generated expression's participants
10228 --that are under ports. This validates the following restrictions:
10229
10230 --If all the nodes participating in the expressions are in the mandatory closure of
10231 --the root, there are no restrictions on the expression.
10232 --Otherwise, we allow only one node which can be multiplied by a constant, which is
10233 --either a literal or a value of a user property.
10234
10235 --A contribution expression that uses a participant which is under an instantiable
10236 --Component or referenced Model cannot also use another participant. Rule ^RULE_NAME
10237 --in the Model ^MODEL_NAME ignored.
10238
10239 report_and_raise_rule_warning(
10240 p_text => CZ_UTILS.GET_TEXT(
10241 CZ_FCE_W_INVALID_CONTRIB,
10242 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
10243 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path)),
10244 p_warning_location => 'generate_expression' );
10245
10246 END IF;
10247
10248 IF ( t_exp_templateid ( j ) = h_templates('subtractsfrom')) THEN
10249
10250 emit_invokevirtual ( 'INumExprDef.neg()');
10251
10252 END IF;
10253
10254 combine_contributors ( l_count );
10255 x_output_context.context_type := const_context_accumulation;
10256
10257 ELSIF ( h_heuristic_ops.EXISTS ( t_exp_templateid ( j ))) THEN
10258
10259 --This is one of the heuristics operators: Assign, DecMax, IncMin, MinFirst or MaxFirst.
10260 --These operators can only be applied to a variable and the decision should be added to
10261 --the model def of this variable's parent.
10262
10263 generate_heuristics ( j, p_input_context, x_output_context );
10264
10265 ELSIF ( h_mathrounding_ops.EXISTS ( t_exp_templateid ( j ))) THEN
10266
10267 generate_mathrounding ( j, p_input_context, x_output_context );
10268
10269 ELSIF ( h_trigonometric_ops.EXISTS ( t_exp_templateid ( j ))) THEN
10270
10271 generate_trigonometric ( j, p_input_context, x_output_context );
10272
10273 ELSIF ( t_exp_templateid ( j ) IN ( h_templates('pow'), h_templates('integerpow'))) THEN
10274
10275 generate_power ( j, p_input_context, x_output_context );
10276
10277 ELSIF ( h_operators_2_text.EXISTS ( t_exp_templateid ( j ))) THEN
10278
10279 --Text comparison operators.
10280
10281 IF ( expr_has_two_children ( l_expr_id )) THEN
10282
10283 l_index := h_exprid_childrenindex ( l_expr_id );
10284
10285 ELSE
10286
10287 report_and_raise_rule_sys_warn(
10288 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_RE_ENODE_TWO_CHILD,
10289 'EXPR_ID', l_expr_id ),
10290 p_warning_location => 'generate_expression');
10291
10292 END IF;
10293
10294 l_aux := l_index + 1;
10295
10296 --Need to skip the totext operator if present.
10297
10298 IF ( is_operator ( l_index, 'totext')) THEN
10299
10300 IF ( expr_has_one_child ( TO_CHAR ( t_exp_exprnodeid ( l_index )))) THEN
10301
10302 l_index := h_exprid_childrenindex ( TO_CHAR ( t_exp_exprnodeid ( l_index )));
10303
10304 ELSE
10305
10306 report_and_raise_rule_sys_warn(
10307 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_RE_ENODE_ONE_CHILD,
10308 'EXPR_ID', TO_CHAR ( t_exp_exprnodeid ( l_index ))),
10309 p_warning_location => 'generate_expression');
10310
10311 END IF;
10312
10313 END IF;
10314
10315 IF ( is_operator ( l_aux, 'totext')) THEN
10316
10317 IF ( expr_has_one_child ( TO_CHAR ( t_exp_exprnodeid ( l_aux )))) THEN
10318
10319 l_aux := h_exprid_childrenindex ( TO_CHAR ( t_exp_exprnodeid ( l_aux )));
10320
10321 ELSE
10322
10323 report_and_raise_rule_sys_warn(
10324 p_text => GET_NOT_TRANSLATED_TEXT( CZ_FCE_SW_RE_ENODE_ONE_CHILD,
10325 'EXPR_ID', TO_CHAR ( t_exp_exprnodeid ( l_aux ))),
10326 p_warning_location => 'generate_expression');
10327
10328 END IF;
10329 END IF;
10330
10331 l_lhs_selection := is_text_selection ( l_index );
10332 l_rhs_selection := is_text_selection ( l_aux );
10333
10334 IF (( l_lhs_selection AND t_exp_exprtype ( l_aux ) <> h_exprtypes ('literal')) OR
10335 ( l_rhs_selection AND t_exp_exprtype ( l_index ) <> h_exprtypes ('literal')))THEN
10336
10337 report_and_raise_rule_sys_warn(
10338 CZ_UTILS.GET_TEXT(CZ_FCE_SW_COMPARE_TXPROP_TXLIT ),
10339 'generate_expression' );
10340
10341 END IF;
10342
10343 l_input_context.context_type := const_context_selection;
10344
10345 c_.combinations.DELETE;
10346 c_.participants.DELETE;
10347
10348 o_.DELETE;
10349 s_.DELETE;
10350 t_.DELETE;
10351
10352 l_side := 0;
10353
10354 IF ( l_lhs_selection ) THEN l_side := 1;
10355 ELSIF ( l_rhs_selection ) THEN l_side := 2; END IF;
10356
10357 generate_expression ( l_index, l_input_context, l_output_context );
10358 generate_expression ( l_aux, l_input_context, l_output_context );
10359
10360 --All the data necessary for generation are already in the corresponding data structures.
10361
10362 generate_text_comparison ( t_exp_templateid ( j ), l_side, p_input_context, x_output_context );
10363
10364 ELSIF ( t_exp_templateid ( j ) = h_templates('none')) THEN
10365
10366 RETURN;
10367
10368 ELSE
10369
10370 --#<should never happen>
10371 -- 'Unknown operator type "^OPERTYPE" in the rule. Rule "^RULE_NAME" in the Model ^MODEL_NAME" ignored.';
10372 report_and_raise_rule_sys_warn(
10373 GET_NOT_TRANSLATED_TEXT(CZ_FCE_SW_UNKNOWN_OP_TYPE,
10374 'OPERTYPE', TO_CHAR(t_exp_templateid ( j ))),
10375 'generate_expression'
10376 );
10377
10378 END IF;
10379
10380 WHEN h_exprtypes ('forall') THEN
10381
10382 generate_statement_forall ( j, p_input_context, x_output_context );
10383
10384 WHEN h_exprtypes ('compatible') THEN
10385
10386 generate_compatible ( j, p_input_context, x_output_context );
10387
10388 WHEN h_exprtypes ('constant') THEN
10389
10390 generate_constant ( j );
10391
10392 ELSE
10393
10394 --#<should never happen>
10395 report_and_raise_rule_sys_warn(
10396 CZ_UTILS.GET_TEXT('CZ_E_UNKNOWN_EXPR_TYPE',
10397 'RULENAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name)),
10398 'generate_expression'
10399 );
10400
10401 END CASE;
10402 END generate_expression;
10403 ----------------------------------------------------------------------------------
10404 PROCEDURE resolve_node ( p_relative_node_path IN VARCHAR2
10405 , p_parent_node_id IN NUMBER
10406 , p_parent_expl_id IN NUMBER
10407 , x_child_node_id IN OUT NOCOPY NUMBER
10408 , x_child_expl_id IN OUT NOCOPY NUMBER
10409 ) IS
10410
10411 l_eff_from DATE := const_epoch_begin;
10412 l_eff_until DATE := const_epoch_end;
10413 l_index PLS_INTEGER;
10414 l_parent_id NUMBER;
10415
10416 l_path_tbl type_number_table;
10417 l_node_tbl type_varchar4000_table;
10418 l_counter NUMBER;
10419
10420 l_return_node_id_tbl type_number_table;
10421 l_return_expl_id_tbl type_number_table;
10422
10423 ----------------------------------------------------------------------------------
10424 PROCEDURE resolve_children ( p_index IN PLS_INTEGER
10425 , p_node_id IN NUMBER
10426 , p_expl_id IN NUMBER
10427 , p_eff_from IN DATE
10428 , p_eff_until IN DATE
10429 ) IS
10430
10431 t_eff_from_tbl type_date_table;
10432 t_eff_until_tbl type_date_table;
10433 t_node_id_tbl type_number_table;
10434 t_expl_id_tbl type_number_table;
10435
10436 l_eff_from_tbl type_date_table;
10437 l_eff_until_tbl type_date_table;
10438 l_node_id_tbl type_number_table;
10439 l_expl_id_tbl type_number_table;
10440 l_path_tbl type_number_table;
10441
10442 l_counter PLS_INTEGER := 0;
10443 l_index PLS_INTEGER;
10444
10445 BEGIN
10446
10447 SELECT ps_node_id, model_ref_expl_id, effective_from, effective_until
10448 BULK COLLECT INTO l_node_id_tbl, l_expl_id_tbl, l_eff_from_tbl, l_eff_until_tbl
10449 FROM cz_explmodel_nodes_v
10450 WHERE model_id = p_component_id
10451 AND parent_psnode_expl_id = p_expl_id
10452 AND effective_parent_id = p_node_id
10453 AND suppress_flag = '0'
10454 AND name = l_node_tbl ( p_index );
10455
10456 FOR i IN 1..l_node_id_tbl.COUNT LOOP
10457
10458 IF ( p_eff_from > l_eff_from_tbl ( i )) THEN l_eff_from_tbl ( i ) := p_eff_from; END IF;
10459 IF ( p_eff_until < l_eff_until_tbl ( i )) THEN l_eff_until_tbl ( i ) := p_eff_until; END IF;
10460
10461 IF( l_eff_from_tbl ( i ) <= l_eff_until_tbl ( i )) THEN
10462
10463 l_counter := l_counter + 1;
10464
10465 t_eff_from_tbl ( l_counter ) := l_eff_from_tbl ( i );
10466 t_eff_until_tbl ( l_counter ) := l_eff_until_tbl ( i );
10467 t_node_id_tbl ( l_counter ) := l_node_id_tbl ( i );
10468 t_expl_id_tbl ( l_counter ) := l_expl_id_tbl ( i );
10469
10470 END IF;
10471 END LOOP;
10472
10473 FOR i IN 1..t_node_id_tbl.COUNT LOOP
10474
10475 IF( p_index = l_node_tbl.COUNT )THEN
10476
10477 l_index := l_return_node_id_tbl.COUNT + 1;
10478
10479 l_return_node_id_tbl ( l_index ) := t_node_id_tbl ( i );
10480 l_return_expl_id_tbl ( l_index ) := t_expl_id_tbl ( i );
10481
10482 ELSE
10483
10484 resolve_children ( p_index + 1, t_node_id_tbl ( i ), t_expl_id_tbl ( i ), t_eff_from_tbl ( i ), t_eff_until_tbl ( i ));
10485
10486 END IF;
10487 END LOOP;
10488 END resolve_children;
10489 ----------------------------------------------------------------------------------
10490 BEGIN
10491
10492 l_node_tbl := split_str_path ( p_relative_node_path );
10493 l_path_tbl := build_reference_path ( p_parent_expl_id );
10494
10495 --Propagate effectivity from all the bom references down from the root model.
10496
10497 FOR i IN 1..l_path_tbl.COUNT LOOP
10498
10499 --We need to stop on the model, in which the rule is defined.
10500
10501 IF ( l_path_tbl ( i ) = p_component_id ) THEN EXIT; END IF;
10502
10503 --Account only for references to bom(s).
10504
10505 l_index := h_psnid_backindex ( l_path_tbl ( i ));
10506
10507 IF ( is_bom_port ( l_index )) THEN
10508
10509 IF ( t_psn_effectivefrom ( l_index ) > l_eff_from ) THEN l_eff_from := t_psn_effectivefrom ( l_index ); END IF;
10510 IF ( t_psn_effectiveuntil ( l_index ) < l_eff_until ) THEN l_eff_until := t_psn_effectiveuntil ( l_index ); END IF;
10511
10512 END IF;
10513 END LOOP;
10514
10515 --Adjust effectivities for the least unambiguous parent.
10516
10517 l_index := h_psnid_backindex(p_parent_node_id);
10518
10519 IF ( t_psn_effectivefrom ( l_index ) > l_eff_from ) THEN l_eff_from := t_psn_effectivefrom ( l_index ); END IF;
10520 IF ( t_psn_effectiveuntil ( l_index ) < l_eff_until ) THEN l_eff_until := t_psn_effectiveuntil ( l_index ); END IF;
10521
10522 --Finally adjust for the rule effectivity.
10523
10524 IF( this_effective_from > l_eff_from)THEN l_eff_from := this_effective_from; END IF;
10525 IF( this_effective_until < l_eff_until)THEN l_eff_until := this_effective_until; END IF;
10526
10527 --If effectivity range is empty, it will be impossible to resolve the node.
10528
10529 IF( l_eff_until < l_eff_from )THEN
10530 -- The reference ^NODE_NAME is invalid. At least one node does not exist in the Model or is not effective when the rule is effective. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
10531 report_and_raise_rule_warning (
10532 CZ_UTILS.GET_TEXT ( CZ_FCE_W_INCORRECT_REFERENCE,
10533 'NODE_NAME', REPLACE (p_relative_node_path, FND_GLOBAL.LOCAL_CHR(7), '.'),
10534 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH( p_component_id, p_model_path ),
10535 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name )),
10536 'RESOLVE_CHILDREN'
10537 );
10538 END IF;
10539
10540 IF( l_node_tbl.COUNT = 0 )THEN
10541
10542 x_child_node_id := p_parent_node_id;
10543 x_child_expl_id := p_parent_expl_id;
10544 RETURN;
10545
10546 END IF;
10547
10548 resolve_children ( 1, p_parent_node_id, p_parent_expl_id, l_eff_from, l_eff_until );
10549
10550 IF ( l_return_node_id_tbl.COUNT = 0 ) THEN
10551 -- The reference ^NODE_NAME is invalid. At least one node does not exist in the Model or is not effective when the rule is effective. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
10552 report_and_raise_rule_warning (
10553 CZ_UTILS.GET_TEXT ( CZ_FCE_W_INCORRECT_REFERENCE,
10554 'NODE_NAME', REPLACE (p_relative_node_path, FND_GLOBAL.LOCAL_CHR(7), '.'),
10555 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH ( p_component_id, p_model_path ),
10556 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name )),
10557 'RESOLVE_CHILDREN'
10558 );
10559
10560 ELSIF ( l_return_node_id_tbl.COUNT > 1 ) THEN
10561 -- Unable to resolve Model node reference ^NODE_NAME because it is ambiguous. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
10562 report_and_raise_rule_warning (
10563 CZ_UTILS.GET_TEXT ( CZ_FCE_W_AMBIGUOUS_REFERENCE,
10564 'NODE_NAME', REPLACE (p_relative_node_path, FND_GLOBAL.LOCAL_CHR(7), '.'),
10565 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH ( p_component_id, p_model_path ),
10566 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name )),
10567 'RESOLVE_CHILDREN'
10568 );
10569
10570 ELSE
10571
10572 x_child_node_id := l_return_node_id_tbl ( 1 );
10573 x_child_expl_id := l_return_expl_id_tbl ( 1 );
10574
10575 END IF;
10576 END resolve_node;
10577 ---------------------------------------------------------------------------------------
10578 BEGIN --> compile_constraints
10579
10580 free_registers ();
10581
10582 SELECT model_ref_expl_id, parent_expl_node_id, component_id, referring_node_id, expl_node_type
10583 BULK COLLECT INTO t_expl_modelrefexplid, t_expl_parentexplnodeid, t_expl_componentid,
10584 t_expl_referringnodeid, t_expl_explnodetype
10585 FROM cz_model_ref_expls
10586 WHERE model_id = p_component_id
10587 AND deleted_flag = '0';
10588
10589 FOR i IN 1..t_expl_modelrefexplid.COUNT LOOP
10590
10591 h_explid_backindex ( TO_CHAR ( t_expl_modelrefexplid ( i ))) := i;
10592
10593 IF ( t_expl_referringnodeid ( i ) IS NOT NULL ) THEN
10594
10595 h_parentid_referring_explid ( TO_CHAR ( t_expl_parentexplnodeid ( i )))( TO_CHAR ( t_expl_referringnodeid ( i ))) := t_expl_modelrefexplid ( i );
10596
10597 END IF;
10598 END LOOP;
10599
10600 FOR rule IN ( SELECT rule_id, rule_type, name, reason_id, rule_folder_id, component_id, model_ref_expl_id,
10601 effective_from, effective_until, effective_usage_mask, effectivity_set_id, invalid_flag,
10602 unsatisfied_msg_id, unsatisfied_msg_source, presentation_flag, rule_class, class_name
10603 FROM cz_rules
10604 WHERE devl_project_id = p_component_id
10605 AND deleted_flag = '0'
10606 AND disabled_flag = '0'
10607 ORDER BY class_seq ) LOOP
10608 BEGIN
10609
10610 this_rule_id := rule.rule_id;
10611 this_reason_id := rule.reason_id;
10612 this_rule_class := rule.rule_class;
10613 this_rule_name := rule.name;
10614 this_effective_from := NVL ( rule.effective_from, const_epoch_begin );
10615 this_effective_until := NVL ( rule.effective_until, const_epoch_end );
10616 this_effective_usages := LPAD ( rule.effective_usage_mask, 16, '0' );
10617
10618 set_rule_savepoint ();
10619
10620 IF ( rule.invalid_flag = '1' ) THEN
10621 IF ( rule.presentation_flag = '0' ) THEN
10622 -- Parsing errors found. Fix parsing errors. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
10623 report_and_raise_rule_warning(
10624 p_text => CZ_UTILS.GET_TEXT (
10625 CZ_FCE_W_PARSE_FAILED,
10626 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name ),
10627 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path)
10628 ),
10629 p_warning_location => 'compile_constraints' );
10630
10631 ELSE
10632
10633 report_and_raise_rule_warning(
10634 -- Invalid or incomplete rule, please check the rule. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
10635 p_text => CZ_UTILS.GET_TEXT (
10636 CZ_FCE_W_TEMPLATE_INVALID,
10637 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name ),
10638 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path)),
10639 p_warning_location => 'compile_constraints' );
10640
10641 END IF;
10642 END IF;
10643
10644 IF ( rule.effectivity_set_id IS NOT NULL ) THEN
10645 IF ( NOT h_effsetid_effectivefrom.EXISTS ( TO_CHAR ( rule.effectivity_set_id ))) THEN
10646
10647 report_and_raise_rule_sys_warn (
10648 p_text => GET_NOT_TRANSLATED_TEXT (
10649 CZ_FCE_SW_RULEINCORRECTEFFSET,
10650 'RULE_NAME',
10651 CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name ),
10652 'MODEL_NAME',
10653 CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH (p_component_id, p_model_path )),
10654 p_warning_location => 'compile_constraints');
10655
10656 ELSE
10657
10658 this_effective_from := h_effsetid_effectivefrom ( TO_CHAR ( rule.effectivity_set_id ));
10659 this_effective_until := h_effsetid_effectiveuntil ( TO_CHAR ( rule.effectivity_set_id ));
10660
10661 END IF;
10662 END IF;
10663
10664 t_exp_modelrefexplid.DELETE;
10665 t_exp_exprtype.DELETE;
10666 t_exp_exprnodeid.DELETE;
10667 t_exp_exprparentid.DELETE;
10668 t_exp_templateid.DELETE;
10669 t_exp_psnodeid.DELETE;
10670 t_exp_datavalue.DELETE;
10671 t_exp_propertyid.DELETE;
10672 t_exp_paramindex.DELETE;
10673 t_exp_argumentindex.DELETE;
10674 t_exp_argumentname.DELETE;
10675 t_exp_datatype.DELETE;
10676 t_exp_datanumvalue.DELETE;
10677 t_exp_paramsignatureid.DELETE;
10678 t_exp_relativenodepath.DELETE;
10679 t_exp_seqnbr.DELETE;
10680
10681 h_exprid_childrenindex.DELETE;
10682 h_exprid_numberofchildren.DELETE;
10683 h_exprid_backindex.DELETE;
10684
10685 IF ( rule.rule_type = h_ruletypes ('statement')) THEN
10686
10687 SELECT model_ref_expl_id, expr_type, expr_node_id, expr_parent_id, template_id, ps_node_id, data_value,
10688 property_id, param_index, argument_index, argument_name, data_type, data_num_value,
10689 param_signature_id, relative_node_path, seq_nbr
10690 BULK COLLECT INTO t_exp_modelrefexplid, t_exp_exprtype, t_exp_exprnodeid, t_exp_exprparentid,
10691 t_exp_templateid, t_exp_psnodeid, t_exp_datavalue, t_exp_propertyid,
10692 t_exp_paramindex, t_exp_argumentindex, t_exp_argumentname, t_exp_datatype,
10693 t_exp_datanumvalue, t_exp_paramsignatureid, t_exp_relativenodepath, t_exp_seqnbr
10694 FROM cz_expression_nodes
10695 WHERE rule_id = rule.rule_id
10696 AND expr_type <> h_exprtypes ('punctuation')
10697 AND deleted_flag = '0'
10698 ORDER BY expr_parent_id, seq_nbr;
10699
10700 l_rule_expr_lastindex := t_exp_exprnodeid.COUNT;
10701
10702 IF ( l_rule_expr_lastindex = 0 ) THEN
10703 -- Rule definition is empty. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
10704 report_and_raise_rule_warning(
10705 p_text => CZ_UTILS.GET_TEXT(
10706 CZ_FCE_W_EMPTY_RULE,
10707 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH(this_rule_id, this_rule_name),
10708 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH(p_component_id, p_model_path) ),
10709 p_warning_location => 'compile_constraints' );
10710
10711 END IF;
10712
10713 FOR i IN 1..l_rule_expr_lastindex LOOP
10714
10715 IF ( t_exp_exprparentid ( i ) IS NOT NULL ) THEN
10716
10717 l_key := TO_CHAR ( t_exp_exprparentid ( i ));
10718
10719 IF( h_exprid_numberofchildren.EXISTS ( l_key ))THEN
10720
10721 h_exprid_numberofchildren ( l_key ) := h_exprid_numberofchildren ( l_key ) + 1;
10722
10723 ELSE
10724
10725 h_exprid_numberofchildren ( l_key ) := 1;
10726
10727 END IF;
10728
10729 IF ( NOT h_exprid_childrenindex.EXISTS ( l_key ))THEN
10730
10731 h_exprid_childrenindex ( l_key ) := i;
10732
10733 END IF;
10734 END IF;
10735
10736 --Sanity check on basic expression node types. May be moved from here to the first pass
10737 --over rules (when implemented).
10738
10739 CASE t_exp_exprtype ( i )
10740
10741 WHEN h_exprtypes ('node') THEN
10742
10743 IF ( t_exp_psnodeid ( i ) IS NULL OR t_exp_modelrefexplid ( i ) IS NULL ) THEN
10744
10745 report_and_raise_rule_sys_warn (
10746 p_text => GET_NOT_TRANSLATED_TEXT (
10747 CZ_FCE_SW_UNDEFINED_STRUC_NODE ),
10748 p_warning_location => 'compile_constraints');
10749
10750 ELSIF ( NOT h_explid_backindex.EXISTS ( TO_CHAR ( t_exp_modelrefexplid ( i )))) THEN
10751
10752 -- Rule participant ^NODE_NAME is not accessible. May be its model reference has been deleted.
10753
10754 report_and_raise_rule_warning (
10755 p_text => CZ_UTILS.GET_TEXT (
10756 CZ_FCE_W_NODE_NOT_FOUND,
10757 'NODE_NAME', CZ_FCE_COMPILE_UTILS.GET_NODE_PATH ( t_exp_psnodeid ( i ),
10758 ps_node_id_table_to_string ( build_model_path ( t_exp_psnodeid ( i )))),
10759 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name ),
10760 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH ( p_component_id, p_model_path )),
10761 p_warning_location => 'compile_constraints');
10762
10763 ELSIF ( NOT h_psnid_backindex.EXISTS ( TO_CHAR ( t_exp_psnodeid ( i )))) THEN
10764
10765 report_and_raise_rule_warning (
10766 p_text => CZ_UTILS.GET_TEXT (
10767 CZ_FCE_W_NODE_DELETED,
10768 'NODE_NAME', CZ_FCE_COMPILE_UTILS.GET_NODE_PATH ( t_exp_psnodeid ( i ),
10769 ps_node_id_table_to_string ( build_model_path ( t_exp_psnodeid ( i )))),
10770 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH( this_rule_id, this_rule_name ),
10771 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH ( p_component_id, p_model_path )),
10772 p_warning_location => 'compile_constraints');
10773
10774 END IF;
10775
10776 WHEN h_exprtypes ('property') THEN
10777
10778 IF ( t_exp_propertyid ( i ) IS NULL ) THEN
10779 -- The rule is incomplete because a property is undefined. Rule ^RULE_NAME in the Model ^MODEL_NAME ignored.
10780 report_and_raise_rule_warning (
10781 p_text => CZ_UTILS.GET_TEXT (
10782 CZ_FCE_W_UNDEFINED_PROPERTY,
10783 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name ),
10784 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH ( p_component_id, p_model_path )),
10785 p_warning_location => 'compile_constraints');
10786
10787 END IF;
10788
10789 WHEN h_exprtypes ('systemproperty') THEN
10790
10791 IF ( t_exp_templateid ( i ) IS NULL ) THEN
10792
10793 report_and_raise_rule_sys_warn(
10794 p_text => GET_NOT_TRANSLATED_TEXT(
10795 CZ_FCE_SW_UNDEFINED_SYS_PROP ),
10796 p_warning_location => 'compile_constraints' );
10797
10798 END IF;
10799
10800 WHEN h_exprtypes ('operator') THEN
10801
10802 IF ( t_exp_templateid ( i ) IS NULL ) THEN
10803
10804 report_and_raise_rule_sys_warn(
10805 p_text => GET_NOT_TRANSLATED_TEXT(
10806 CZ_FCE_SW_UNDEFINED_OPERATOR ),
10807 p_warning_location => 'compile_constraints' );
10808
10809 END IF;
10810
10811 WHEN h_exprtypes ('template') THEN
10812
10813 IF ( t_exp_templateid ( i ) IS NULL ) THEN
10814
10815 report_and_raise_rule_sys_warn(
10816 p_text => GET_NOT_TRANSLATED_TEXT(
10817 CZ_FCE_SW_UNDEFINED_OP_TEMPL ),
10818 p_warning_location => 'compile_constraints' );
10819
10820 END IF;
10821
10822 WHEN h_exprtypes ('operatorbyname') THEN
10823
10824 IF ( t_exp_argumentname ( i ) IS NULL ) THEN
10825
10826 report_and_raise_rule_sys_warn(
10827 p_text => GET_NOT_TRANSLATED_TEXT(
10828 CZ_FCE_SW_UNDEFINED_OP_BY_NAME ),
10829 p_warning_location => 'compile_constraints' );
10830
10831 END IF;
10832
10833 WHEN h_exprtypes ('nodebyname') THEN
10834
10835 resolve_node ( p_relative_node_path => t_exp_relativenodepath ( i )
10836 , p_parent_node_id => t_exp_psnodeid ( i )
10837 , p_parent_expl_id => t_exp_modelrefexplid ( i )
10838 , x_child_node_id => t_exp_psnodeid ( i )
10839 , x_child_expl_id => t_exp_modelrefexplid ( i )
10840 );
10841
10842 t_exp_exprtype ( i ) := h_exprtypes ('node');
10843
10844 ELSE NULL;
10845 END CASE;
10846
10847 h_exprid_backindex ( TO_CHAR ( t_exp_exprnodeid ( i ))) := i;
10848
10849 END LOOP;
10850
10851 FOR i IN 1..l_rule_expr_lastindex LOOP
10852
10853 --One statement rule can contain several constraints. Right now, if there is a problem
10854 --in any of these constraints, the whole rule will be ignored. This is why it is ok to
10855 --set the savepoint for the whole rule at the beginning. If we want to ignore specific
10856 --constraint within a rule we need to set and restore savepoints inside this loop.
10857
10858 IF ( t_exp_exprparentid ( i ) IS NULL ) THEN
10859
10860 comment ( 'Create rule: "' || this_rule_name || '" (rule_id = ' || this_rule_id || ')');
10861
10862 --These arrays are per constraint.
10863
10864 h_instancequantifiers.DELETE;
10865 t_instancequantifiers.DELETE;
10866 h_parameter_stack.DELETE;
10867
10868 --All assistant variables by definition are used only within a constraint.
10869
10870 assistant_var_id := 0;
10871
10872 --Put the ModelDef on the stack for the last addConstraint call.
10873
10874 aload_model_def ( p_component_id );
10875
10876 l_output_context.context_type := const_context_generic;
10877 l_input_context.context_type := const_context_generic;
10878
10879 generate_expression ( i, l_input_context, l_output_context );
10880
10881 IF ( l_output_context.context_type NOT IN ( const_context_accumulation
10882 , const_context_forall
10883 , const_context_compatible
10884 , const_context_heuristics
10885 )) THEN
10886
10887 set_reason_id ();
10888 add_constraint ();
10889
10890 ELSE
10891
10892 --In case of accumulator rule, we need to remove the model def, put on the stack
10893 --before expression generation, as we did not add the constraint yet.
10894 --In the case of ForAll all the constraints are already added so we also need to
10895 --remove the model def.
10896
10897 emit_pop ( 1 );
10898
10899 END IF;
10900 END IF;
10901 END LOOP;
10902
10903 ELSIF ( rule.rule_type = h_ruletypes ('explicitcompat')) THEN
10904
10905 --Instance quantifiers are initialized inside the procedure as necessary.
10906
10907 generate_explicit_compat ( l_input_context, l_output_context );
10908
10909 ELSIF ( rule.rule_type = h_ruletypes ('designchart')) THEN
10910
10911 --Instance quantifiers are initialized inside the procedure as necessary.
10912
10913 generate_design_chart ( l_input_context, l_output_context );
10914
10915 ELSIF ( rule.rule_type = h_ruletypes ('companion')) THEN
10916
10917 l_run_id := x_run_id;
10918 CZ_DEVELOPER_UTILS_PVT.verify_special_rule( this_rule_id, this_rule_name, l_run_id );
10919
10920 END IF; --> rule type
10921
10922 EXCEPTION --> compile_constraints block
10923 WHEN CZ_LOGICGEN_WARNING THEN
10924 restore_rule_savepoint ();
10925 WHEN CZ_LOGICGEN_SYS_WARNING THEN
10926 restore_rule_savepoint ();
10927 WHEN CZ_LOGICGEN_ERROR THEN
10928 RAISE;
10929 WHEN CZ_LOGICGEN_SYS_ERROR THEN
10930 RAISE;
10931 WHEN OTHERS THEN
10932 report_and_raise_sys_error (
10933 p_message => GET_NOT_TRANSLATED_TEXT ( CZ_FCE_SE_UNKNOWN_IN_RULE,
10934 'RULE_NAME', CZ_FCE_COMPILE_UTILS.GET_RULE_PATH ( this_rule_id, this_rule_name )),
10935 p_run_id => x_run_id,
10936 p_model_id => p_component_id,
10937 p_error_stack => DBMS_UTILITY.FORMAT_ERROR_STACK || ' Error backtrace: ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
10938 );
10939 END;
10940 END LOOP;
10941
10942 --Now handle all the accumulator rules, defined in the model, if any.
10943 --Accumulator rules can only be constraints.
10944
10945 IF ( t_acc_targets.COUNT > 0 ) THEN
10946
10947 --Target is not just a node but includes some of the properties that can be applied, for example,
10948 --MinInstances()/MaxInstances(), applied to the same target component, will be different targets.
10949
10950 FOR i IN 1..t_acc_targets.COUNT LOOP
10951
10952 FOR j IN 1..t_acc_contributors ( i ).COUNT LOOP
10953
10954 --We need to skip dummy contribution records that may have been created when combining
10955 --effectivity intervals.
10956
10957 IF ( t_acc_contributors ( i )( j ).interval_key IS NOT NULL ) THEN
10958
10959 --Model def for addConstraint method.
10960
10961 aload_model_def ( p_component_id );
10962
10963 l_count := t_acc_contributors ( i )( j ).quantifiers.COUNT;
10964
10965 IF ( l_count > 0 ) THEN
10966
10967 --Will need another model def for the ForAll.
10968
10969 emit_dup ();
10970
10971 FOR jj IN 1..l_count LOOP
10972
10973 aload_register ( t_acc_contributors ( i )( j ).quantifiers ( jj ));
10974
10975 END LOOP;
10976
10977 IF ( l_count > 2 ) THEN
10978
10979 create_array ( l_count, h_javatypes ('IInstanceQuantifier'));
10980 populate_array ( l_count );
10981
10982 END IF;
10983 END IF;
10984
10985 aload_register ( t_acc_targets ( i ));
10986 aload_register ( t_acc_contributors ( i )( j ).interval_key );
10987 emit_invokevirtual('INumExprDef.eq(INumExprDef)');
10988
10989 --Set the violation message to the generic seeded message.
10990
10991 emit_dup ();
10992
10993 push_long_constant ( const_textid_resultnotvalid );
10994 emit_invokevirtual('IExprDef.setId(long)');
10995
10996 --Remove the null object from stack after a void method.
10997
10998 emit_pop ( 1 );
10999 emit_effectivity ( 'ILogicExprDef', t_acc_contributors ( i )( j ).effective_from, t_acc_contributors ( i )( j ).effective_until, t_acc_contributors ( i )( j ).effective_usage_mask );
11000
11001 IF ( l_count > 0 ) THEN
11002
11003 emit_invokevirtual ( CASE l_count
11004 WHEN 1 THEN 'IModelDef.forAll(IInstanceQuantifier, ILogicExprDef)'
11005 WHEN 2 THEN 'IModelDef.forAll(IInstanceQuantifier, IInstanceQuantifier, ILogicExprDef)'
11006 ELSE 'IModelDef.forAll(IInstanceQuantifier[], ILogicExprDef)'
11007 END );
11008
11009 emit_invokevirtual('IModelDef.addConstraint(IForAllDef)');
11010
11011 ELSE
11012
11013 emit_invokevirtual('IModelDef.addConstraint(ILogicExprDef)');
11014
11015 END IF;
11016
11017 emit_pop ( 1 );
11018
11019 END IF;
11020 END LOOP;
11021 END LOOP;
11022 END IF;
11023 END compile_constraints;
11024 ---------------------------------------------------------------------------------------
11025 BEGIN --> compile_logic_file
11026
11027 init_logic_file ();
11028 h_devlid_modelvisited ( TO_CHAR ( p_component_id )) := 1;
11029
11030 ----------------------------------------------------------------------------------
11031 CASE p_type WHEN const_logicfile_def THEN
11032 ----------------------------------------------------------------------------------
11033 LOOP
11034
11035 v_index := v_index + 1;
11036
11037 CASE t_psn_psnodetype(v_index)
11038
11039 WHEN h_psntypes('component') THEN --> component
11040
11041 emit_model_def (v_index);
11042
11043 WHEN h_psntypes('feature') THEN --> feature
11044
11045 CASE t_psn_featuretype ( v_index )
11046
11047 WHEN h_psntypes ('booleanfeature') THEN
11048
11049 emit_logicvar ( v_index );
11050
11051 WHEN h_psntypes ('integerfeature') THEN
11052
11053 emit_intvar ( v_index
11054 , NVL ( t_psn_minimum ( v_index ), cz_fce_compile_utils.const_min_integer )
11055 , NVL ( t_psn_maximum ( v_index ), cz_fce_compile_utils.const_max_integer )
11056 );
11057
11058 WHEN h_psntypes ('decimalfeature') THEN
11059
11060 emit_floatvar ( v_index
11061 , NVL ( t_psn_minimum ( v_index ), const_min_double )
11062 , NVL ( t_psn_maximum ( v_index ), const_max_double )
11063 );
11064
11065 WHEN h_psntypes ('optionfeature') THEN
11066
11067 --Code will be generated when the last option is reached. Here just initialize the option count
11068 --and store the feature index.
11069
11070 l_feature_idx := v_index;
11071 l_var_min := NVL ( t_psn_minimum ( v_index ), 0 );
11072
11073 IF ( h_psnid_numberofchildren ( TO_CHAR ( t_psn_psnodeid ( v_index ))) > 0 ) THEN
11074
11075 l_option_count := h_psnid_numberofchildren ( TO_CHAR ( t_psn_psnodeid ( v_index )));
11076
11077 ELSE
11078
11079 IF ( l_var_min > 0 ) THEN
11080 -- Invalid problem definition: Option Feature with minimum quantity greater than 0 must have children. The Option Feature is ^NODE_NAME in the Model ^MODEL_NAME.
11081 report_and_raise_error(
11082 p_message => CZ_UTILS.GET_TEXT ( CZ_FCE_E_OPTION_MAXQ_NO_CHILD,
11083 'NODE_NAME', CZ_FCE_COMPILE_UTILS.GET_NODE_PATH(t_psn_psnodeid ( v_index ),
11084 ps_node_id_table_to_string(
11085 build_model_path(t_psn_psnodeid ( v_index ) ) ) ),
11086 'MODEL_NAME', CZ_FCE_COMPILE_UTILS.GET_MODEL_PATH( p_component_id, p_model_path) ),
11087 p_run_id => x_run_id,
11088 p_model_id => p_component_id
11089 );
11090
11091 END IF;
11092
11093 l_option_count := 0;
11094
11095 END IF;
11096
11097 l_var_max := NVL ( t_psn_maximum ( v_index ), l_option_count );
11098 l_var_count := NVL ( t_psn_maxqtyperoption ( v_index ), 1 );
11099
11100 --This procedure puts the first two parameters to the feature's method on the stack.
11101
11102 prepare_feature ( v_index );
11103
11104 IF ( l_option_count = 0 ) THEN
11105
11106 --This is a valid feature with no options, need to create the variable here.
11107
11108 create_feature ( v_index, l_option_count, l_var_min, l_var_max, l_var_count );
11109
11110 END IF;
11111
11112 ELSE NULL;
11113
11114 END CASE;
11115
11116 WHEN h_psntypes('option') THEN --> option
11117
11118 push_variable_name ( v_index );
11119
11120 IF ( v_index = h_psnid_lastchildindex ( TO_CHAR ( t_psn_parentid ( v_index )))) THEN
11121
11122 --This is the last option of the feature, create the feature after that.
11123
11124 create_feature ( l_feature_idx, l_option_count, l_var_min, l_var_max, l_var_count );
11125
11126 END IF;
11127
11128 WHEN h_psntypes('total') THEN --> total
11129
11130 emit_floatvar ( v_index
11131 , NVL ( t_psn_minimum ( v_index ), const_min_double )
11132 , NVL ( t_psn_maximum ( v_index ), const_max_double )
11133 );
11134
11135 WHEN h_psntypes('resource') THEN --> resource
11136
11137 emit_floatvar ( v_index
11138 , NVL ( t_psn_minimum ( v_index ), 0 )
11139 , NVL ( t_psn_maximum ( v_index ), const_max_double )
11140 );
11141
11142 WHEN h_psntypes('integertotal') THEN --> integer total
11143
11144 emit_intvar ( v_index
11145 , NVL ( t_psn_minimum ( v_index ), cz_fce_compile_utils.const_min_integer )
11146 , NVL ( t_psn_maximum ( v_index ), cz_fce_compile_utils.const_max_integer )
11147 );
11148
11149 WHEN h_psntypes('integerresource') THEN --> integer resource
11150
11151 emit_intvar ( v_index
11152 , NVL ( t_psn_minimum ( v_index ), 0 )
11153 , NVL ( t_psn_maximum ( v_index ), cz_fce_compile_utils.const_max_integer )
11154 );
11155
11156 WHEN h_psntypes('bommodel') THEN --> bom model
11157
11158 emit_bommodel_def ( v_index, NVL ( t_psn_decimalqtyflag( v_index ), '0' ));
11159
11160 --Bug #6613028. If the bom model is not root, need to create a variable here.
11161
11162 --This is the same code as for a bom reference in the port file generation, except for
11163 --using ps_node_id instead of reference_id.
11164
11165 IF ( t_psn_parentid ( v_index ) IS NOT NULL ) THEN
11166
11167 --See Section 23.13.2 'BOM Instantiatibility and Quantity' in
11168 --http://files.oraclecorp.com/content/AllPublic/SharedFolders/CZ-Dev-Project-Documents-Public/12.1/Design/CZ_CP_Engine_UI_FD.doc
11169
11170 IF ( t_psn_instantiableflag ( v_index ) = h_instantiability ('mandatory')) THEN
11171
11172 l_var_min := 1;
11173 l_var_max := 1;
11174
11175 ELSIF ( t_psn_instantiableflag ( v_index ) = h_instantiability ('optional')) THEN
11176
11177 l_var_min := 0;
11178 l_var_max := 1;
11179
11180 ELSE
11181
11182 l_var_min := 0;
11183 l_var_max := NVL ( t_psn_maximumselected( v_index ), cz_fce_compile_utils.const_max_integer);
11184
11185 END IF;
11186
11187 l_begin_date := NVL ( t_psn_effectivefrom ( v_index ), const_epoch_begin );
11188 l_end_date := NVL ( t_psn_effectiveuntil ( v_index ), const_epoch_end );
11189
11190 IF ( l_begin_date < const_epoch_begin ) THEN l_begin_date := const_epoch_begin; END IF;
11191 IF ( l_end_date > const_epoch_end ) THEN l_end_date := const_epoch_end; END IF;
11192
11193 --Note, that the value of the decimal quantity flag is taken using ps_node_id, not reference_id,
11194 --because we are on the model node, not reference node.
11195
11196 emit_bommodelvar ( v_index
11197 , NVL ( h_psnid_decimalqtyflag ( TO_CHAR ( t_psn_psnodeid ( v_index ))), '0')
11198 , NVL ( t_psn_bomrequiredflag ( v_index ), '0')
11199 , NVL ( t_psn_minimumselected ( v_index ), 0 )
11200 , NVL ( t_psn_maximumselected ( v_index ), cz_fce_compile_utils.const_max_integer)
11201 , NVL ( t_psn_initialnumvalue ( v_index ), 0 )
11202 , l_var_min
11203 , l_var_max
11204 , l_begin_date
11205 , l_end_date
11206 , LPAD ( t_psn_effectiveusagemask ( v_index ), 16, '0')
11207 );
11208 END IF;
11209
11210 WHEN h_psntypes('bomoptionclass') THEN --> bom option class
11211
11212 emit_bomoptionclass_def( v_index, NVL ( t_psn_decimalqtyflag(v_index), '0'));
11213
11214 l_begin_date := NVL ( t_psn_effectivefrom(v_index), const_epoch_begin);
11215 l_end_date := NVL ( t_psn_effectiveuntil(v_index), const_epoch_end);
11216
11217 IF ( l_begin_date < const_epoch_begin) THEN l_begin_date := const_epoch_begin; END IF;
11218 IF ( l_end_date > const_epoch_end) THEN l_end_date := const_epoch_end; END IF;
11219
11220 --Bug #7039221.
11221
11222 l_var_max := 1;
11223
11224 IF ( NVL ( t_psn_maximumselected ( v_index ), -1 ) = -1 ) THEN
11225
11226 l_var_max := h_psnid_numberofchildren ( TO_CHAR ( t_psn_psnodeid ( v_index )));
11227
11228 END IF;
11229
11230 emit_bomoptionclassvar ( v_index
11231 , NVL ( t_psn_decimalqtyflag ( v_index ), '0')
11232 , NVL ( t_psn_bomrequiredflag ( v_index ), '0')
11233 , NVL ( t_psn_minimum ( v_index ), 0 )
11234 , NVL ( t_psn_maximum ( v_index ), cz_fce_compile_utils.const_max_integer )
11235 , NVL ( t_psn_initialnumvalue ( v_index ), 0 )
11236 , NVL ( t_psn_minimumselected ( v_index ), 0 )
11237 , l_var_max
11238 , l_begin_date
11239 , l_end_date
11240 , LPAD ( t_psn_effectiveusagemask ( v_index ), 16, '0' )
11241 );
11242
11243 WHEN h_psntypes('bomstandard') THEN --> bom standard item
11244
11245 l_begin_date := NVL ( t_psn_effectivefrom(v_index), const_epoch_begin);
11246 l_end_date := NVL ( t_psn_effectiveuntil(v_index), const_epoch_end);
11247
11248 IF ( l_begin_date < const_epoch_begin) THEN l_begin_date := const_epoch_begin; END IF;
11249 IF ( l_end_date > const_epoch_end) THEN l_end_date := const_epoch_end; END IF;
11250
11251 emit_bomstandarditemvar ( v_index
11252 , NVL ( t_psn_decimalqtyflag(v_index), '0')
11253 , NVL ( t_psn_bomrequiredflag (v_index), '0')
11254 , NVL ( t_psn_minimum(v_index), 0)
11255 , NVL ( t_psn_maximum(v_index), cz_fce_compile_utils.const_max_integer)
11256 , NVL ( t_psn_initialnumvalue(v_index), 0)
11257 , l_begin_date
11258 , l_end_date
11259 , LPAD ( t_psn_effectiveusagemask( v_index ), 16, '0' )
11260 );
11261
11262 WHEN h_psntypes('beginstructure') THEN --> begin structure data
11263
11264 IF (NOT h_devlid_modelvisited.EXISTS ( TO_CHAR ( t_psn_devlprojectid (v_index)))) THEN
11265 IF p_model_path IS NULL OR p_model_path = '' THEN
11266 l_model_path := t_psn_name ( v_index - 1 );
11267 ELSE
11268 l_model_path := p_model_path || '/' || t_psn_name ( v_index - 1 );
11269 END IF;
11270
11271 compile_logic_file ( t_psn_devlprojectid ( v_index ), const_logicfile_def, l_model_path );
11272
11273 END IF;
11274
11275 WHEN h_psntypes('beginport') THEN --> begin port variables
11276
11277 compile_logic_file ( p_component_id, const_logicfile_port, p_model_path );
11278
11279 WHEN h_psntypes('beginrule') THEN --> begin port variables
11280
11281 compile_logic_file ( p_component_id, const_logicfile_constraint, p_model_path );
11282
11283 WHEN h_psntypes('endstructure') THEN --> end structure data
11284
11285 EXIT;
11286
11287 ELSE
11288
11289 NULL;
11290
11291 END CASE;
11292 END LOOP;
11293 ----------------------------------------------------------------------------------
11294 WHEN const_logicfile_port THEN
11295 ----------------------------------------------------------------------------------
11296 LOOP
11297 v_index := v_index + 1;
11298
11299 CASE t_psn_psnodetype(v_index)
11300
11301 WHEN h_psntypes('component') THEN --> component
11302
11303 IF (t_psn_virtualflag ( v_index ) = h_instantiability ('nonvirtual')) THEN --> component instance
11304
11305 emit_instancesetvar ( v_index, t_psn_minimum(v_index), t_psn_maximum(v_index));
11306
11307 ELSE --> mandatory component
11308
11309 emit_singletonvar (v_index);
11310
11311 END IF; --> component
11312
11313 WHEN h_psntypes('reference') THEN --> reference
11314
11315 IF ( h_psnid_psnodetype ( TO_CHAR ( t_psn_referenceid (v_index))) = h_psntypes('bommodel')) THEN --> reference to BOM
11316
11317 --See Section 23.13.2 'BOM Instantiatibility and Quantity' in
11318 --http://files.oraclecorp.com/content/AllPublic/SharedFolders/CZ-Dev-Project-Documents-Public/12.1/Design/CZ_CP_Engine_UI_FD.doc
11319
11320 IF ( t_psn_instantiableflag ( v_index ) = h_instantiability ('mandatory')) THEN
11321
11322 l_var_min := 1;
11323 l_var_max := 1;
11324
11325 ELSIF ( t_psn_instantiableflag ( v_index ) = h_instantiability ('optional')) THEN
11326
11327 l_var_min := 0;
11328 l_var_max := 1;
11329
11330 ELSE
11331
11332 l_var_min := 0;
11333 l_var_max := NVL ( t_psn_maximumselected(v_index), cz_fce_compile_utils.const_max_integer);
11334
11335 END IF;
11336
11337 l_begin_date := NVL ( t_psn_effectivefrom(v_index), const_epoch_begin );
11338 l_end_date := NVL ( t_psn_effectiveuntil(v_index), const_epoch_end );
11339
11340 IF ( l_begin_date < const_epoch_begin) THEN l_begin_date := const_epoch_begin; END IF;
11341 IF ( l_end_date > const_epoch_end) THEN l_end_date := const_epoch_end; END IF;
11342
11343 emit_bommodelvar ( v_index
11344 , NVL ( h_psnid_decimalqtyflag ( TO_CHAR ( t_psn_referenceid (v_index))), '0')
11345 , NVL ( t_psn_bomrequiredflag (v_index), '0')
11346 , NVL ( t_psn_minimumselected(v_index), 0)
11347 , NVL ( t_psn_maximumselected(v_index), cz_fce_compile_utils.const_max_integer)
11348 , NVL ( t_psn_initialnumvalue(v_index), 0)
11349 , l_var_min
11350 , l_var_max
11351 , l_begin_date
11352 , l_end_date
11353 , LPAD ( t_psn_effectiveusagemask ( v_index ), 16, '0' )
11354 );
11355
11356 ELSE --> component reference
11357
11358 emit_instancesetvar ( v_index, t_psn_minimum(v_index), t_psn_maximum(v_index));
11359
11360 END IF;
11361
11362 WHEN h_psntypes('connector') THEN --> connector
11363
11364 emit_connectorsetvar ( v_index, t_psn_minimum(v_index), t_psn_maximum(v_index));
11365
11366 WHEN h_psntypes('endport') THEN --> end port variables
11367
11368 EXIT;
11369
11370 ELSE
11371
11372 NULL;
11373
11374 END CASE;
11375 END LOOP;
11376 ----------------------------------------------------------------------------------
11377 WHEN const_logicfile_constraint THEN
11378 ----------------------------------------------------------------------------------
11379
11380 --First generate all reverse port relations defined in the structure, then compile
11381 --constraints.
11382
11383 l_reverseportcount := 0;
11384
11385 LOOP
11386 v_index := v_index + 1;
11387
11388 CASE t_psn_psnodetype(v_index)
11389
11390 WHEN h_psntypes('endrule') THEN --> end port variables
11391
11392 EXIT;
11393
11394 ELSE
11395
11396 emit_reverseport ( v_index );
11397 l_reverseportcount := l_reverseportcount + 1;
11398
11399 END CASE;
11400 END LOOP;
11401
11402 --#<optimization-reverseport>: Pop the nulls here in bulk.
11403
11404 emit_pop ( l_reverseportcount );
11405
11406 compile_constraints ();
11407 ----------------------------------------------------------------------------------
11408 END CASE;
11409
11410 emit_return ();
11411 spool_logic_file ();
11412
11413 END compile_logic_file;
11414 ---------------------------------------------------------------------------------------
11415 BEGIN --> compile_logic_
11416
11417 IF ( x_run_id IS NULL OR x_run_id = 0 ) THEN
11418
11419 SELECT cz_xfr_run_infos_s.NEXTVAL INTO x_run_id FROM DUAL;
11420
11421 END IF;
11422
11423 --Read effectivity sets into memory and build hash tables for quick lookup.
11424
11425 SELECT effectivity_set_id, effective_from, effective_until
11426 BULK COLLECT INTO t_effset_effectivitysetid, t_effset_effectivefrom, t_effset_effectiveuntil
11427 FROM cz_effectivity_sets
11428 WHERE deleted_flag = '0';
11429
11430 FOR i IN 1..t_effset_effectivitysetid.COUNT LOOP
11431
11432 h_effsetid_effectivefrom ( TO_CHAR ( t_effset_effectivitysetid ( i ))) := t_effset_effectivefrom ( i );
11433 h_effsetid_effectiveuntil ( TO_CHAR ( t_effset_effectivitysetid ( i ))) := t_effset_effectiveuntil ( i );
11434
11435 END LOOP;
11436
11437 --Pass 1. Process the model data to transform it into the internal format.
11438
11439 v_index := 1;
11440 h_devlid_modelvisited.DELETE;
11441 read_model_data ( p_object_id );
11442
11443 --Pass 2. Compilation.
11444
11445 v_index := 1;
11446 h_devlid_modelvisited.DELETE;
11447 compile_logic_file ( p_object_id, const_logicfile_def );
11448
11449 IF ( p_two_phase_commit = 0 ) THEN COMMIT; END IF;
11450
11451 EXCEPTION
11452 WHEN CZ_LOGICGEN_ERROR THEN
11453 ROLLBACK;
11454 WHEN CZ_LOGICGEN_SYS_ERROR THEN
11455 ROLLBACK;
11456 WHEN OTHERS THEN
11457 ROLLBACK;
11458 -- Unknown Error:
11459 report_and_raise_sys_error(
11460 p_message => CZ_UTILS.GET_TEXT(CZ_FCE_UE_GENERIC_PREFIX) || DBMS_UTILITY.FORMAT_ERROR_STACK,
11461 p_run_id => x_run_id,
11462 p_model_id => p_object_id,
11463 p_error_stack => DBMS_UTILITY.FORMAT_ERROR_STACK || ' Error backtrace: ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE,
11464 p_raise_exception => FALSE
11465 );
11466
11467 END compile_logic_;
11468 ---------------------------------------------------------------------------------------
11469 --Default method to generate logic in debug mode.
11470
11471 PROCEDURE debug_logic ( p_object_id IN NUMBER
11472 , x_run_id IN OUT NOCOPY NUMBER
11473 ) IS
11474 BEGIN
11475
11476 compile_logic_ ( p_object_id, x_run_id, 0, 1 );
11477
11478 END debug_logic;
11479 ---------------------------------------------------------------------------------------
11480 --Default method to generate logic for a model in the database.
11481
11482 PROCEDURE compile_logic ( p_object_id IN NUMBER
11483 , x_run_id IN OUT NOCOPY NUMBER
11484 ) IS
11485 BEGIN
11486
11487 compile_logic_ ( p_object_id, x_run_id, 0, 0 );
11488
11489 END compile_logic;
11490 ---------------------------------------------------------------------------------------
11491 --This method is not required in FCE as there is no DDL in generation of property-based
11492 --compatibility rules (Re: bug #2028790). The caller of this method is responsible for
11493 --commiting the generated logic to the database.
11494
11495 PROCEDURE compile_logic__ ( p_object_id IN NUMBER
11496 , p_run_id IN NUMBER
11497 ) IS
11498 l_run_id NUMBER := p_run_id;
11499
11500 BEGIN
11501
11502 compile_logic_ ( p_object_id, l_run_id, 1, 0 );
11503
11504 END compile_logic__;
11505 ---------------------------------------------------------------------------------------
11506 BEGIN
11507
11508 CZ_FCE_DATA.populate_fce_data ();
11509
11510 END;