DBA Data[Home] [Help]

PACKAGE BODY: APPS.IGS_RU_GEN_002

Source


1 PACKAGE BODY IGS_RU_GEN_002 AS
2 /* $Header: IGSRU02B.pls 115.19 2003/09/04 08:06:40 rghosh ship $ */
3 
4 Function Rulp_Ins_Parser(
5   p_group IN NUMBER ,
6   p_return_type IN VARCHAR2 ,
7   p_rule_description IN VARCHAR2 ,
8   p_rule_processed IN OUT NOCOPY VARCHAR2 ,
9   p_rule_unprocessed IN OUT NOCOPY VARCHAR2 ,
10   p_generate_rule IN BOOLEAN ,
11   p_rule_number IN OUT NOCOPY NUMBER ,
12   p_LOV_number IN OUT NOCOPY NUMBER )
13 RETURN BOOLEAN IS
14   ------------------------------------------------------------------
15   --Created by  : nsinha, Oracle India
16   --Date created: 12-Mar-1999
17   --
18   --Purpose: Parses the Rule Text for Syntax Checking.
19   --
20   --Known limitations/enhancements and/or remarks:
21   --
22   --Change History:
23   --Who         When            What
24   --Nsinha      12-Mar-2002     Bug # 2233951: Changed the reference of
25   --                            IGS_RU_GEN_003 and IGS_GE_GEN_004 with IGS_RU_GEN_006
26   --
27   -------------------------------------------------------------------
28 /*
29  STRUCTURES
30 */
31 TYPE t_number IS TABLE OF
32 	NUMBER(6)
33 INDEX BY BINARY_INTEGER;
34 TYPE r_LOV IS RECORD (
35 	select_item	IGS_RU_DESCRIPTION.rule_description%TYPE,
36 	description	VARCHAR2(2000),
37 	selectable	VARCHAR2(1) );
38 TYPE t_LOV IS TABLE OF
39 	r_LOV
40 INDEX BY BINARY_INTEGER;
41 TYPE t_param_list IS TABLE OF
42 	IGS_RU_RET_TYPE.s_return_type%TYPE
43 INDEX BY BINARY_INTEGER;
44 
45 /*
46  CONSTANTS
47 */
48 cst_space	CONSTANT VARCHAR2(1) := fnd_global.local_chr(31);
49 cst_spacemod	CONSTANT VARCHAR2(1) := fnd_global.local_chr(9);
50 /*
51  GLOBALS
52 */
53 gv_level	NUMBER(3);
54 gv_set_number	IGS_RU_SET.sequence_number%TYPE;
55 gv_min_rule	NUMBER;
56 /*
57  when delete rule, keep rule numbers to reuse
58 */
59 gt_rule_numbers	t_number;
60 gv_rn_index	NUMBER;
61 /*
62  when delete rule, keep set numbers to reuse
63 */
64 gt_set_numbers	t_number;
65 gv_sn_index	NUMBER;
66 /*
67  table of selectable items
68 */
69 gt_rule_LOV	t_LOV;
70 gv_LOV_index	NUMBER;
71 /*
72  list of parameter return types
73 */
74 gt_param_list	t_param_list;
75 gv_params	NUMBER;
76 gv_param_type	IGS_RU_RET_TYPE.s_return_type%TYPE;
77 /*
78  string termiate character
79 */
80 gv_string_terminate	VARCHAR2(10);
81 /*
82  selected value in LOV's
83 */
84 gv_prev		VARCHAR2(100);
85 gv_pprev	VARCHAR2(100);
86 gv_select_count	NUMBER := 0;
87 /*
88 
89  FORWARD REFERENCE DECLARATIONS
90 
91 */
92 FUNCTION parse_rule(
93 	p_type		IN VARCHAR2,
94 	p_rule		IN OUT NOCOPY VARCHAR2,
95 	p_rule_number	IN NUMBER,
96 	p_item		IN OUT NOCOPY NUMBER)
97 RETURN BOOLEAN;
98 /*
99 
100  MISCELLANEOUS FUNCTIONS
101 
102 */
103 
104 /*
105 
106  maintain LOV array
107 
108 */
109 PROCEDURE make_LOV(
110 	p_rule		IN VARCHAR2,
111 	p_string	IN VARCHAR2,
112 	p_description	IN VARCHAR2,
113 	p_selectable	IN VARCHAR2)
114 IS
115 BEGIN DECLARE
116 	v_rule_length	NUMBER;
117 BEGIN
118 /*
119  RETURN;
120 */
121 	v_rule_length := LENGTH(p_rule);
122 	IF v_rule_length IS NULL
123 	THEN
124 		v_rule_length := 0;
125 	END IF;
126 	IF v_rule_length < gv_min_rule
127 	THEN
128 /*
129 		 start again
130 */
131 		gv_min_rule := v_rule_length;
132 		gv_LOV_index := 0;
133 	END IF;
134 	IF v_rule_length = gv_min_rule
135 	THEN
136 		gv_LOV_index := gv_LOV_index + 1;
137 		gt_rule_LOV(gv_LOV_index).select_item := REPLACE(p_string,fnd_global.local_chr(10));
138 		gt_rule_LOV(gv_LOV_index).description := p_description;
139 		gt_rule_LOV(gv_LOV_index).selectable := p_selectable;
140 	END IF;
141 END;
142 END make_LOV;
143 /*
144 
145  one item, no directives
146  return item or null
147 
148 */
149 FUNCTION LOV_item
150 RETURN VARCHAR2 IS
151 	v_description	IGS_RU_LOV.description%TYPE;
152 	v_selectable	IGS_RU_LOV.selectable%TYPE;
153 BEGIN
154 	SELECT	description,
155 		selectable
156 	INTO	v_description,
157 		v_selectable
158 	FROM	IGS_RU_LOV
159 	WHERE	sequence_number = p_LOV_number;
160 	IF v_selectable = 'Y'
161 	THEN
162 		RETURN v_description;
163 	END IF;
164 	RETURN NULL;
165 	EXCEPTION
166 		WHEN TOO_MANY_ROWS THEN
167 			RETURN NULL;
168 END LOV_item;
169 /*
170 
171  move LOV's to table
172 
173 */
174 PROCEDURE insert_LOV_tab
175 IS
176 X_ROWID  VARCHAR2(25);
177 v_help_text	igs_ru_lov.help_text%TYPE;
178 CURSOR C_RL IS
179 	SELECT ROWID, rl.*
180 	FROM IGS_RU_LOV rl
181 	WHERE SEQUENCE_NUMBER = p_LOV_number ;
182 
183 BEGIN
184 	IF p_LOV_number IS NULL
185 	THEN
186 		SELECT	IGS_RU_LOV_SEQ_NUM_S.nextval
187 		INTO	p_LOV_number
188 		FROM	DUAL;
189 	END IF;
190 
191 	FOR C_RL_REC IN C_RL LOOP
192 		IGS_RU_LOV_PKG.DELETE_ROW (X_ROWID => C_RL_REC.ROWID	);
193 	END LOOP;
194 
195 
196 	FOR v_index IN 1 .. gv_LOV_index
197 	LOOP
198 	BEGIN
199 		IGS_RU_LOV_PKG.INSERT_ROW (
200 		X_ROWID => X_ROWID,
201 		X_SEQUENCE_NUMBER => p_LOV_number,
202 		X_DESCRIPTION     => LTRIM(RTRIM(gt_rule_LOV(v_index).select_item)),
203 		X_HELP_TEXT       => LTRIM(RTRIM(gt_rule_LOV(v_index).description)),
204 		X_SELECTABLE      => LTRIM(RTRIM(gt_rule_LOV(v_index).selectable)) );
205 
206 		EXCEPTION
207 			WHEN DUP_VAL_ON_INDEX THEN
208 /*
209 				NULL;
210 				 order of descriptions (better this way)
211 */
212 				UPDATE	igs_ru_lov
213 				SET	help_text = LTRIM(RTRIM(gt_rule_LOV(v_index).description))
214 				WHERE	sequence_number = p_LOV_number
215 				AND	description = LTRIM(RTRIM(gt_rule_LOV(v_index).select_item));
216 
217 	END;
218 	END LOOP;
219 END insert_LOV_tab;
220 /*
221 
222  make new rule
223 
224 */
225 FUNCTION new_rule
226   ------------------------------------------------------------------
227   --Created by  : nsinha, Oracle India
228   --Date created: 12-Mar-2002
229   --
230   --Purpose:
231   --
232   --
233   --Known limitations/enhancements and/or remarks:
234   --
235   --Change History:
236   --Who         When            What
237   --nsinha      12-Mar-2002     Bug# 2233951: Modified the logic to
238   --                            SELECT the next value of the sequence number
239   --                            differently when the data is for SEED DB.
240   --
241   -------------------------------------------------------------------
242 RETURN NUMBER IS
243 BEGIN DECLARE
244 	v_rule_number	NUMBER;
245 	X_ROWID  		VARCHAR2(25);
246 
247 	CURSOR C_IGS_RU_RULE_SEQ_NUM_S IS
248         SELECT igs_ru_rule_seq_num_s.NEXTVAL
249 	FROM   DUAL;
250 
251      CURSOR cur_max_plus_one IS
252       SELECT   (sequence_number + 1) sequence_number
253       FROM     igs_ru_rule
254       WHERE    sequence_number =
255         (SELECT   MAX (sequence_number)
256          FROM     igs_ru_rule
257          WHERE    sequence_number < 499999)
258       FOR UPDATE OF sequence_number NOWAIT;
259 
260 BEGIN
261 	IF p_generate_rule = FALSE
262 	THEN
263 		RETURN NULL;
264 	END IF;
265 	IF gv_rn_index = 0
266 	THEN
267           --
268 	  --  New description number
269           --  If the User creating this record is DATAMERGE (id = 1) then
270           --    Get the sequence as the existing maximum value + 1
271           --  Else
272           --    Get the next value from the database sequence
273           --
274           IF (fnd_global.user_id = 1) THEN
275             OPEN  cur_max_plus_one;
276             FETCH cur_max_plus_one INTO v_rule_number;
277             CLOSE cur_max_plus_one;
278           ELSE
279             OPEN C_IGS_RU_RULE_SEQ_NUM_S;
280             FETCH C_IGS_RU_RULE_SEQ_NUM_S INTO v_rule_number;
281             CLOSE C_IGS_RU_RULE_SEQ_NUM_S;
282           END IF;
283 	ELSE
284            /*
285 		 use deleted rule number
286            */
287 		v_rule_number := gt_rule_numbers(gv_rn_index);
288 		gv_rn_index := gv_rn_index - 1;
289 	END IF;
290 
291       IGS_RU_RULE_PKG.INSERT_ROW (
292 	X_ROWID		 => X_ROWID ,
293  	X_SEQUENCE_NUMBER	 => V_RULE_NUMBER );
294 
295 	RETURN v_rule_number;
296 END;
297 END new_rule;
298 /*
299 
300  insert new set
301 
302 */
303 FUNCTION new_set (
304 	p_set_type	IN IGS_RU_SET.set_type%TYPE )
305 RETURN NUMBER IS
306 BEGIN DECLARE
307 	v_set_number	NUMBER;
308 	X_ROWID		VARCHAR2(25);
309 
310 	CURSOR C_IGS_RU_SET_SEQ_NUM_S IS
311         SELECT igs_ru_set_seq_num_s.NEXTVAL
312 	FROM   DUAL;
313 
314      CURSOR cur_max_plus_one IS
315       SELECT   (sequence_number + 1) sequence_number
316       FROM     igs_ru_set
317       WHERE    sequence_number =
318         (SELECT   MAX (sequence_number)
319          FROM     igs_ru_set
320          WHERE    sequence_number < 499999)
321       FOR UPDATE OF sequence_number NOWAIT;
322 BEGIN
323 	IF p_generate_rule = FALSE
324 	THEN
325 		RETURN NULL;
326 	END IF;
327 	IF gv_sn_index = 0 THEN
328 	  --
329 	  --  New description number
330           --  If the User creating this record is DATAMERGE (id = 1) then
331           --    Get the sequence as the existing maximum value + 1
332           --  Else
333           --    Get the next value from the database sequence
334           --
335           IF (fnd_global.user_id = 1) THEN
336             OPEN  cur_max_plus_one;
337             FETCH cur_max_plus_one INTO v_set_number;
338             CLOSE cur_max_plus_one;
339           ELSE
340             OPEN C_IGS_RU_SET_SEQ_NUM_S;
341             FETCH C_IGS_RU_SET_SEQ_NUM_S INTO v_set_number;
342             CLOSE C_IGS_RU_SET_SEQ_NUM_S;
343           END IF;
344 	ELSE
345           /*
346 		 use deleted set number
347           */
348 		v_set_number := gt_set_numbers(gv_sn_index);
349 		gv_sn_index := gv_sn_index - 1;
350 	END IF;
351 
352       IGS_RU_SET_PKG.INSERT_ROW (
353 	X_ROWID => X_ROWID,
354 	X_SEQUENCE_NUMBER  => v_set_number,
355 	X_SET_TYPE         => p_set_type );
356 
357 	RETURN v_set_number;
358 END;
359 END new_set;
360 /*
361 
362  consume leading spaces and tabs, return rest of string
363 
364 */
365 PROCEDURE consume_leading_spaces(
366 	p_rule		IN OUT NOCOPY VARCHAR2)
367 IS
368 	v_first		NUMBER;
369 BEGIN
370 /*
371 	 skip internal space and tab
372 */
373 	v_first := 1;
374 	WHILE SUBSTR(p_rule,v_first,1) = cst_space
375 	OR    SUBSTR(p_rule,v_first,1) = '	'
376 	LOOP
377 		v_first := v_first + 1;
378 	END LOOP;
379 	p_rule := SUBSTR(p_rule,v_first);
380 END consume_leading_spaces;
381 /*
382 
383  consume unit code
384  make LOV
385 
386 */
387 FUNCTION consume_unit_code(
388 	p_rule		IN OUT NOCOPY VARCHAR2)
389 RETURN BOOLEAN IS
390 	v_char		VARCHAR2(1);
391 	v_count		NUMBER;
392 	v_no_units	BOOLEAN := TRUE;
393 	v_unit_cd	IGS_PS_UNIT_VER.unit_cd%TYPE := '%4$@G!))^';
394 	v_max_count	NUMBER;
395 BEGIN
396 	gv_select_count := 0;
397 	consume_leading_spaces(p_rule);
398 	FOR v_ii IN 1 .. 200 /*LENGTH(p_rule)*/
399 	LOOP
400 		v_char := SUBSTR(p_rule,v_ii,1);
401 		IF v_char = ','		/* next set member*/
402 		OR v_char = '.'		/* versions       */
403 		OR v_char = '}' 	/* end of set     */
404 		OR v_char = cst_space	/* internal space */
405 		OR v_char IS NULL	/* end of line    */
406 		THEN
407 			IF v_ii = 1
408 			THEN
409 				/* invalid first char, no unit*/
410 				make_LOV(p_rule,
411 					'*** Valid Unit Code ***',
412 					'Input part or all of a valid unit code.',
413 					'N');
414 				RETURN FALSE;
415 			ELSE
416 				/* count the number of units selected, remember their might be wildcards*/
417 				SELECT	count(*)
418 				INTO	v_count
419 				FROM	IGS_PS_UNIT_VER
420 				/*WHERE	unit_cd LIKE UPPER(SUBSTR(p_rule,1,v_ii - 1)); --Bug 2395891/2543627 --space not accepted in user defined rules*/
421 				WHERE	unit_cd LIKE UPPER(SUBSTR(REPLACE(p_rule,cst_spacemod,' '),1,v_ii - 1)); --nshee
422 				IF v_count = 0
423 				THEN
424 /*
425 					 check if to many selected units (1000)
426 */
427 					SELECT	count(*)
428 					INTO	v_max_count
429 					FROM	IGS_PS_UNIT_VER
430 					/*WHERE	unit_cd LIKE UPPER(SUBSTR(p_rule,1,v_ii - 1))||'%'; --Bug 2395891/2543627 --space not accepted in user defined rules*/
431 					WHERE	unit_cd LIKE UPPER(SUBSTR(REPLACE(p_rule,cst_spacemod,' '),1,v_ii - 1))||'%';--nshee
432 					IF v_max_count > 1000
433 					THEN
434 						make_LOV(p_rule,
435 							'*** To many units selected. ***',
436 							'Suggest you restrict the select criteria further.',
437 							'N');
438 						RETURN FALSE;
439 					END IF;
440 /*
441 					 build list of values using the first few chars
442 */
443 					FOR uv IN (
444 						SELECT	unit_cd,
445 							version_number,
446 							unit_status,
447 							short_title
448 						FROM	IGS_PS_UNIT_VER
449 						/*WHERE	unit_cd LIKE UPPER(SUBSTR(p_rule,1,v_ii - 1))||'%' --Bug 2395891/2543627 --space not accepted in user defined rules*/
450 						WHERE	unit_cd LIKE UPPER(SUBSTR(REPLACE(p_rule,cst_spacemod,' '),1,v_ii - 1))||'%' --nshee
451 						ORDER BY unit_cd,version_number DESC )
452 					LOOP
453 						v_no_units := FALSE;
454 						IF uv.unit_cd <> v_unit_cd
455 						THEN
456 /*
457 							 latest version of new unit code
458 */
459 							make_LOV(p_rule,
460 								uv.unit_cd,
461 								uv.short_title||'   (ALL VERSIONS)',
462 								'Y');
463 						END IF;
464 						v_unit_cd := uv.unit_cd;
465 /*
466 						 list all versions
467 */
468 						make_LOV(p_rule,
469 							uv.unit_cd||'.'||IGS_GE_NUMBER.TO_CANN(uv.version_number),
470 							uv.short_title||'   ('||uv.unit_status||')',
471 							'Y');
472 					END LOOP;
473 					IF v_no_units
474 					THEN
475 						make_LOV(p_rule,
476 							'*** Valid Unit Code ***',
477 							'Input part or all of a valid unit code.',
478 							'N');
479 					ELSE
480 						gv_select_count := v_ii - 1;
481 					END IF;
482 					RETURN FALSE;
483 				ELSE
484 /*
485 					 found unit(s)
486 */
487 					p_rule := SUBSTR(p_rule,v_ii);
488 					RETURN TRUE;
489 				END IF;
490 			END IF;
491 		END IF;
492 	END LOOP;
493 /*
494 	 end of line
495 */
496 	p_rule := NULL;
497 	RETURN TRUE;
498 END consume_unit_code;
499 /*
500 
501  consume unit set code
502 
503 */
504 FUNCTION consume_us_code(
505 	p_rule		IN OUT NOCOPY VARCHAR2)
506 RETURN BOOLEAN IS
507 BEGIN DECLARE
508 	v_char		VARCHAR2(1);
509 	v_count		NUMBER;
510 	v_no_units	BOOLEAN := TRUE;
511 	v_unit_set_cd	IGS_EN_UNIT_SET.unit_set_cd%TYPE := '#@*&!Vv9(';
512 	v_max_count	NUMBER;
513 BEGIN
514 	consume_leading_spaces(p_rule);
515 	FOR v_ii IN 1 .. 200
516 	LOOP
517 		v_char := SUBSTR(p_rule,v_ii,1);
518 		IF v_char = ','		/* next set member  */
519 		OR v_char = '.'		/* versions	      */
520 		OR v_char = '}' 	/* end of set       */
521 		OR v_char = cst_space	/* internal space   */
522 		OR v_char IS NULL	/* end of line      */
523 		THEN
524 			IF v_ii = 1
525 			THEN
526 /*
527 				 invalid first char, no unit set
528 */
529 				make_LOV(p_rule,'*** Valid Unit Set Code ***',
530 					'Input part or all of a valid unit set code.',
531 					'N');
532 				RETURN FALSE;
533 			ELSE
534 /*
535 				 count the number of UNIT sets selected, remember their might be wildcards
536 */
537 				SELECT	count(*)
538 				INTO	v_count
539 				FROM	IGS_EN_UNIT_SET
540 /*				WHERE	unit_set_cd LIKE UPPER(SUBSTR(p_rule,1,v_ii - 1)); commented by nshee as part of fix of bug 2381638 and 2395891 and added the next line */
541 				WHERE	unit_set_cd LIKE UPPER(SUBSTR(REPLACE(p_rule,cst_spacemod,' '),1,v_ii - 1));
542 				IF v_count = 0
543 				THEN
544 /*
545 					 check if to many selected set members (1000)
546 */
547 					SELECT	count(*)
548 					INTO	v_max_count
549 					FROM	IGS_EN_UNIT_SET
550 					/*WHERE	unit_set_cd LIKE UPPER(SUBSTR(p_rule,1,v_ii - 1))||'%';--Bug 2395891/2543627 --space not accepted in user defined rules*/
551 					WHERE	unit_set_cd LIKE UPPER(SUBSTR(REPLACE(p_rule,cst_spacemod,' '),1,v_ii - 1))||'%';--nshee
552 					IF v_max_count > 1000
553 					THEN
554 						make_LOV(p_rule,
555 							'*** To many unit sets selected. ***',
556 							'Suggest you restrict the select criteria further.',
557 							'N');
558 						RETURN FALSE;
559 					END IF;
560 /*
561 					 build list of values using the first few chars
562 */
563 					FOR us IN (
564 						SELECT	unit_set_cd,
565 							version_number,
566 							unit_set_status,
567 							short_title
568 						FROM	IGS_EN_UNIT_SET
569 						/*WHERE	unit_set_cd LIKE UPPER(SUBSTR(p_rule,1,v_ii - 1))||'%'--Bug 2395891/2543627 --space not accepted in user defined rules*/
570 						WHERE	unit_set_cd LIKE UPPER(SUBSTR(REPLACE(p_rule,cst_spacemod,' '),1,v_ii - 1))||'%'--nshee
571 						ORDER BY unit_set_cd,version_number DESC )
572 					LOOP
573 						v_no_units := FALSE;
574 						IF us.unit_set_cd <> v_unit_set_cd
575 						THEN
576 /*
577 							 latest version of new unit code
578 */
579 							make_LOV(p_rule,us.unit_set_cd,
580 								us.short_title||'   (ALL VERSIONS)',
581 								'Y');
582 						END IF;
583 						v_unit_set_cd := us.unit_set_cd;
584 /*
585 						 list all versions
586 */
587 						make_LOV(p_rule,us.unit_set_cd||'.'||IGS_GE_NUMBER.TO_CANN(us.version_number),
588 							us.short_title||'   ('||us.unit_set_status||')',
589 							'Y');
590 					END LOOP;
591 					IF v_no_units
592 					THEN
593 						make_LOV(p_rule,'*** Valid Unit Set Code ***',
594 							'Input part or all of a valid unit set code.',
595 							'N');
596 					END IF;
597 					RETURN FALSE;
598 				ELSE
599 /*
600 					 found unit(s)
601 */
602 					p_rule := SUBSTR(p_rule,v_ii);
603 					RETURN TRUE;
604 				END IF;
605 			END IF;
606 		END IF;
607 	END LOOP;
608 /*
609 	 end of line
610 */
611 	p_rule := NULL;
612 	RETURN TRUE;
613 END;
614 END consume_us_code;
615 /*
616 
617  consume course code
618  make LOV
619 
620 */
621 FUNCTION consume_crs_code(
622 	p_rule		IN OUT NOCOPY VARCHAR2)
623 RETURN BOOLEAN IS
624 	v_char		VARCHAR2(1);
625 	v_count		NUMBER;
626 	v_no_members	BOOLEAN := TRUE;
627 	v_member_cd	IGS_PS_VER.course_cd%TYPE := '%4@!)^';
628 	v_max_count	NUMBER;
629 BEGIN
630 	consume_leading_spaces(p_rule);
631 	FOR v_ii IN 1 .. 200 /*LENGTH(p_rule) */
632 	LOOP
633 		v_char := SUBSTR(p_rule,v_ii,1);
634 		IF v_char = ','		/* next set member */
635 		OR v_char = '.'		/* versions        */
636 		OR v_char = '}' 	/* end of set      */
637 		OR v_char = cst_space	/* internal space  */
638 		OR v_char IS NULL	/* end of line     */
639 		THEN
640 			IF v_ii = 1
641 			THEN
642 /*
643 				 invalid first char, no member(s)
644 */
645 				make_LOV(p_rule,
646 					'*** Valid Course Code ***',
647 					'Input part or all of a valid course code.',
648 					'N');
649 				RETURN FALSE;
650 			ELSE
651 /*
652 				 count the number of members selected, remember their might be wildcards
653 */
654 				SELECT	count(*)
655 				INTO	v_count
656 				FROM	IGS_PS_VER
657 				/*WHERE	course_cd LIKE UPPER(SUBSTR(p_rule,1,v_ii - 1));--Bug 2395891/2543627 --space not accepted in user defined rules*/
658 				WHERE	course_cd LIKE UPPER(SUBSTR(REPLACE(p_rule,cst_spacemod,' '),1,v_ii - 1));--nshee
659 				IF v_count = 0
660 				THEN
661 /*
662 					 check if to many selected set members (1000)
663 */
664 					SELECT	count(*)
665 					INTO	v_max_count
666 					FROM	IGS_PS_VER
667 					/*WHERE	course_cd LIKE UPPER(SUBSTR(p_rule,1,v_ii - 1))||'%';--Bug 2395891/2543627 --space not accepted in user defined rules*/
668 					WHERE	course_cd LIKE UPPER(SUBSTR(REPLACE(p_rule,cst_spacemod,' '),1,v_ii - 1))||'%';--nshee
669 					IF v_max_count > 1000
670 					THEN
671 						make_LOV(p_rule,
672 							'*** To many courses selected. ***',
673 							'Suggest you restrict the select criteria further.',
674 							'N');
675 						RETURN FALSE;
676 					END IF;
677 /*
678 					 build list of values using the first few chars
679 */
680 					FOR cv IN (
681 						SELECT	course_cd,
682 							version_number,
683 							course_status,
684 							short_title
685 						FROM	IGS_PS_VER
686 						/*WHERE	course_cd LIKE UPPER(SUBSTR(p_rule,1,v_ii - 1))||'%'--Bug 2395891/2543627 --space not accepted in user defined rules*/
687 						WHERE	course_cd LIKE UPPER(SUBSTR(REPLACE(p_rule,cst_spacemod,' '),1,v_ii - 1))||'%'--nshee
688 						ORDER BY course_cd,version_number DESC )
689 					LOOP
690 						v_no_members := FALSE;
691 						IF cv.course_cd <> v_member_cd
692 						THEN
693 /*
694 							 latest version of new member code
695 */
696 							make_LOV(p_rule,
697 								cv.course_cd,
698 								cv.short_title||'   (ALL VERSIONS)',
699 								'Y');
700 						END IF;
701 						v_member_cd := cv.course_cd;
702 /*
703 						 list all versions
704 */
705 						make_LOV(p_rule,
706 							cv.course_cd||'.'||IGS_GE_NUMBER.TO_CANN(cv.version_number),
707 							cv.short_title||'   ('||cv.course_status||')',
708 							'Y');
709 					END LOOP;
710 					IF v_no_members
711 					THEN
712 						make_LOV(p_rule,
713 							'*** Valid Course Code ***',
714 							'Input part or all of a valid course code.',
715 							'N');
716 					END IF;
717 					RETURN FALSE;
718 				ELSE
719 /*
720 					 found members(s)
721 */
722 					p_rule := SUBSTR(p_rule,v_ii);
723 					RETURN TRUE;
724 				END IF;
725 			END IF;
726 		END IF;
727 	END LOOP;
728 /*
729 	 end of line
730 */
731 	p_rule := NULL;
732 	RETURN TRUE;
733 END consume_crs_code;
734 /*
735 
736  rationalise versions {AAC101.1,AAC101,2} => {AAC101.[1-2]}
737  order the versions string 10-12,4,7,5 => 4-5,7,10-12
738  versions of form 7-2 are nonsense and will be ignored
739 
740 */
741 FUNCTION do_versions (
742 	p_current_versions	VARCHAR2,
743 	p_extra_versions	VARCHAR2 )
744 RETURN VARCHAR2 IS
745 	v_concat_versions	VARCHAR2(200);
746 	v_prev_comma		NUMBER := 1;	/* previous position of comma in string */
747 	v_curr_comma		NUMBER;		/* current position of comma in string  */
748 	v_sub_str		VARCHAR2(30);	/* sub-string between comma's           */
749 	v_dash			NUMBER;		/* position of '-' in sub-string        */
750 	v_lower			NUMBER;
751 	v_upper			NUMBER;
752 	vt_version		t_number;	/* array of version numbers             */
753 	v_max_ver		NUMBER := 0;
754 	v_new_versions		IGS_RU_SET_MEMBER.versions%TYPE;
755 BEGIN
756 	IF p_current_versions IS NULL OR
757 	   p_extra_versions IS NULL
758 	THEN
759 /*
760 		 null mean ALL versions
761 */
762 		RETURN NULL;
763 	END IF;
764 /*
765 	 breakdown the versions string and build the versions array
766 */
767 	v_concat_versions := p_current_versions||','||p_extra_versions;
768 	LOOP
769 /*
770 		 find next comma (if exists)
771 */
772         	v_curr_comma := INSTR(v_concat_versions, ',', v_prev_comma);
773         	IF v_curr_comma = 0
774         	THEN
775 /*
776 			 all/rest of string
777 */
778 			v_sub_str := SUBSTR(v_concat_versions, v_prev_comma);
779 		ELSE
780 /*
781 			 part of string, previous comma to this comma
782 */
783 			v_sub_str := SUBSTR(v_concat_versions, v_prev_comma,
784 						v_curr_comma - v_prev_comma);
785 		END IF;
786         	v_prev_comma := v_curr_comma + 1;
787 /*
788         	 find next dash in sub-string (if exists)
789 */
790 		v_dash := INSTR(v_sub_str, '-');
791         	IF v_dash = 0
792         	THEN
793 			v_lower := IGS_GE_NUMBER.TO_NUM(v_sub_str);
794 			v_upper := v_lower;
795 		ELSE
796 /*
797 			 dash in sub-string, split lower and upper
798 */
799 			v_lower := IGS_GE_NUMBER.TO_NUM(SUBSTR(v_sub_str, 1, v_dash - 1));
800 			v_upper := IGS_GE_NUMBER.TO_NUM(SUBSTR(v_sub_str, v_dash + 1));
801 		END IF;
802 		IF v_lower IS NOT NULL
803 		THEN
804 /*
805 			 populate array
806 */
807 			FOR v_ii IN 1 .. v_upper - v_lower + 1
808 			LOOP
809 /*
810 				 array index and value are the same
811 */
812 				vt_version(v_ii + v_lower - 1) := v_ii + v_lower - 1;
813 			END LOOP;
814 			IF v_max_ver < v_upper
815 			THEN
816 /*
817 				 set max version
818 */
819 				v_max_ver := v_upper;
820 			END IF;
821 		END IF;
822         	IF v_curr_comma = 0
823         	THEN
824 			EXIT;
825 		END IF;
826 	END LOOP;
827 /*
828 	 rebuild the versions string from the versions array
829 */
830 	v_lower := NULL;
831 	FOR v_ii IN 1 .. v_max_ver + 1
832 	LOOP
833 	BEGIN
834 		IF v_lower IS NULL
835 		THEN
836 			v_lower := vt_version(v_ii);
837 			v_upper := vt_version(v_ii);
838 		ELSE
839 			v_upper := vt_version(v_ii);
840 		END IF;
841 		EXCEPTION
842 		WHEN NO_DATA_FOUND THEN
843 			IF v_lower IS NOT NULL
844 			THEN
845 				IF v_new_versions IS NOT NULL
846 				THEN
847 /*
848 					 there's more therefor add comma
849 */
850 					v_new_versions := v_new_versions||',';
851 				END IF;
852 				IF v_lower = v_upper
853 				THEN
854 /*
855 					 single version
856 */
857 					v_new_versions := v_new_versions||IGS_GE_NUMBER.TO_CANN(v_lower);
858 				ELSE
859 /*
860 					 range
861 */
862 					v_new_versions := v_new_versions||IGS_GE_NUMBER.TO_CANN(v_lower)||'-'||IGS_GE_NUMBER.TO_CANN(v_upper);
863 				END IF;
864 			END IF;
865 			v_lower := NULL;
866 	END;
867 	END LOOP;
868 	RETURN v_new_versions;
869 END do_versions;
870 /*
871 
872  insert set member
873 
874 */
875 PROCEDURE insert_set_member(
876 	p_set_number	IN IGS_RU_SET.sequence_number%TYPE,
877 	p_unit		IN VARCHAR2)
878 IS
879 	v_unit			VARCHAR2(200);
880 	v_dot			NUMBER;
881 	v_unit_cd		IGS_RU_SET_MEMBER.unit_cd%TYPE;
882 	v_versions		VARCHAR2(100); /* bigger to allow for spaces etc*/
883 	v_current_versions	IGS_RU_SET_MEMBER.versions%TYPE;
884 	v_new_versions		IGS_RU_SET_MEMBER.versions%TYPE;
885 	X_ROWID			VARCHAR2(25);
886 
887 	CURSOR C_RSMBR IS
888 	SELECT ROWID, rsmbr.*
889 	FROM   IGS_RU_SET_MEMBER rsmbr
890 	WHERE	rs_sequence_number = p_set_number
891 	AND	unit_cd = v_unit_cd;
892 
893 BEGIN
894 	IF p_generate_rule = FALSE
895 	THEN
896 		RETURN;
897 	END IF;
898 /*
899 	 remove spaces and tabs
900 */
901 	v_unit := REPLACE(p_unit,cst_space);
902         v_unit := UPPER(REPLACE(v_unit,cst_spacemod,' '));/*added this line by nshee as fix for bug 2395891*/
903 	v_unit := UPPER(REPLACE(v_unit,'	'));
904 	v_dot := INSTR(v_unit,'.');
905 	IF v_dot = 0
906 	THEN
907 		v_unit_cd := v_unit;
908 	ELSE
909 		v_unit_cd := RTRIM(SUBSTR(v_unit,1,v_dot - 1));
910 		v_versions := SUBSTR(v_unit,v_dot + 1);
911 /*
912 		 remove brackets '[', ']' (range)
913 */
914 		v_versions := REPLACE(v_versions,'[');
915 		v_versions := REPLACE(v_versions,']');
916 	END IF;
917 	IF v_unit_cd IS NOT NULL
918 	THEN
919 		IGS_RU_SET_MEMBER_PKG.INSERT_ROW (
920 		X_ROWID			=>	X_ROWID,
921 		X_RS_SEQUENCE_NUMBER    =>	p_set_number,
922 		X_UNIT_CD               =>	v_unit_cd,
923 		X_VERSIONS              =>	v_versions );
924 
925 	END IF;
926 	EXCEPTION
927 	WHEN DUP_VAL_ON_INDEX THEN
928 		SELECT	versions
929 		INTO	v_current_versions
930 		FROM	IGS_RU_SET_MEMBER
931 		WHERE	rs_sequence_number = p_set_number
932 		AND	unit_cd = v_unit_cd;
933 /*
934 		 rationalise new versions with existing versions
935 
936 */
937 		  v_new_versions := do_versions(v_current_versions,v_versions);
938 
939 		FOR C_RSMBR_REC IN C_RSMBR LOOP
940                    IGS_RU_SET_MEMBER_PKG.UPDATE_ROW (
941 			X_ROWID 			=> C_RSMBR_REC.ROWID,
942 			X_RS_SEQUENCE_NUMBER	=> C_RSMBR_REC.RS_SEQUENCE_NUMBER,
943 			X_UNIT_CD               => C_RSMBR_REC.UNIT_CD ,
944 			X_VERSIONS              => v_new_versions );
945 		END LOOP;
946 
947 END insert_set_member;
948 /*
949 
950  get a number
951 
952 */
953 FUNCTION get_number (
954 	p_number	OUT NOCOPY NUMBER,
955 	p_rule		IN OUT NOCOPY VARCHAR2 )
956 RETURN BOOLEAN IS
957 	v_first		NUMBER;	/* first non white space      */
958 	v_count		NUMBER;	/* count until next non number*/
959 BEGIN
960 	IF p_rule IS NULL
961 	THEN
962 		RETURN FALSE;
963 	END IF;
964 /*
965 	 skip internal space and tab
966 */
967 	v_first := 1;
968 	WHILE SUBSTR(p_rule,v_first,1) = cst_space
969 	OR    SUBSTR(p_rule,v_first,1) = '	'
970 	LOOP
971 		v_first := v_first + 1;
972 	END LOOP;
973 /*
974 	 check until end of line or VALUE_ERROR
975 */
976 	v_count := 0;
977 	LOOP
978 	BEGIN
979 		v_count := v_count + 1;
980 		IF SUBSTR(p_rule,v_first + v_count - 1) IS NULL
981 		THEN
982 			EXIT;
983 		END IF;
984 /*
985 		 convert and validate number
986 */
987 		p_number := IGS_GE_NUMBER.TO_NUM(SUBSTR(p_rule,v_first,v_count));
988 		EXCEPTION
989 			WHEN VALUE_ERROR THEN
990 				EXIT;
991 	END;
992 	END LOOP;
993 	IF v_count > 1
994 	THEN
995 /*
996 		 count > 1 therefor must have number
997 		 consume rule string
998 */
999 		p_rule := SUBSTR(p_rule,v_first + v_count - 1);
1000 		RETURN TRUE;
1001 	END IF;
1002 	RETURN FALSE;
1003 END get_number;
1004 /*
1005 
1006  get string until next quote
1007 
1008 */
1009 FUNCTION get_string (
1010 	p_string	OUT NOCOPY VARCHAR2,
1011 	p_rule		IN OUT NOCOPY VARCHAR2,
1012 	p_terminate	IN VARCHAR2 )
1013 RETURN BOOLEAN IS
1014 	v_quote	NUMBER;
1015 BEGIN
1016 	IF p_rule IS NULL
1017 	THEN
1018 		RETURN FALSE;
1019 	END IF;
1020 	v_quote := INSTR(p_rule,p_terminate);
1021 	IF v_quote = 0
1022 	THEN
1023 		p_string := p_rule;
1024 		p_rule := '';
1025 	ELSE
1026 		p_string := SUBSTR(p_rule,1,v_quote - 1);
1027 		p_rule := SUBSTR(p_rule,v_quote);
1028 	END IF;
1029 	RETURN TRUE;
1030 END get_string;
1031 /*
1032 
1033  get date and validate
1034 
1035 */
1036 FUNCTION get_date (
1037 	p_string	IN OUT NOCOPY VARCHAR2,
1038 	p_rule		IN OUT NOCOPY VARCHAR2 )
1039 RETURN BOOLEAN IS
1040 	v_rule		VARCHAR2(2000);
1041 	v_date_format	VARCHAR2(30);
1042 BEGIN
1043 	v_rule := p_rule;
1044 /*
1045 	 this assumes terminate string is same as commencement string?
1046 */
1047 	IF get_string(p_string,p_rule,gv_string_terminate) = TRUE AND
1048 	   IGS_RU_GEN_006.jbsp_get_dt_picture(REPLACE(p_string,cst_space),v_date_format) = TRUE
1049 	THEN
1050 		RETURN TRUE;
1051 	END IF;
1052 	p_rule := v_rule;
1053 	RETURN FALSE;
1054 END get_date;
1055 /*
1056 
1057  match string to part of rule ignoring spaces,
1058  set ramainder of rule and return TRUE
1059  else FALSE
1060 
1061 */
1062 FUNCTION match_string_to_rule(
1063 	p_string	IN VARCHAR2,
1064 	p_rule		IN OUT NOCOPY VARCHAR2)
1065 RETURN BOOLEAN IS
1066 BEGIN DECLARE
1067 	v_string	IGS_RU_DESCRIPTION.rule_description%TYPE;
1068 	v_string_length	NUMBER;
1069 	v_sub_rule	IGS_RU_DESCRIPTION.rule_description%TYPE;
1070 BEGIN
1071 	IF p_rule IS NULL
1072 	THEN
1073 		RETURN FALSE;
1074 	END IF;
1075 	v_string := REPLACE(p_string,' ');
1076 	v_string := REPLACE(v_string,fnd_global.local_chr(10));
1077 	v_string := REPLACE(v_string,'	');
1078 	v_string_length := LENGTH(v_string);
1079 	FOR v_ii IN v_string_length .. LENGTH(p_rule)
1080 	LOOP
1081 /*
1082 		 remove internal spaces
1083 */
1084 		v_sub_rule := REPLACE(SUBSTR(p_rule,1,v_ii),cst_space);
1085 /*
1086 		 remove returns
1087 */
1088 		v_sub_rule := REPLACE(v_sub_rule,fnd_global.local_chr(10));
1089 /*
1090 		 remove tabs
1091 */
1092 		v_sub_rule := REPLACE(v_sub_rule,'	');
1093 		IF LENGTH(v_sub_rule) = v_string_length
1094 		THEN
1095 			IF v_string = v_sub_rule
1096 			THEN
1097 				p_rule := LTRIM(SUBSTR(p_rule,v_ii + 1));
1098 				RETURN TRUE;
1099 			ELSE
1100 				RETURN FALSE;
1101 			END IF;
1102 		END IF;
1103 	END LOOP;
1104 	RETURN FALSE;
1105 END;
1106 END match_string_to_rule;
1107 /*
1108 
1109  convert the description string into token, action
1110  string, action, remainder of description
1111  string, NULL, NULL
1112  NULL, action, remainder of description
1113 
1114  return FALSE if description is NULL
1115 
1116 */
1117 FUNCTION breakdown_desc (
1118 	p_string	IN OUT NOCOPY IGS_RU_DESCRIPTION.rule_description%TYPE,
1119 	p_action	IN OUT NOCOPY IGS_RU_DESCRIPTION.s_return_type%TYPE,
1120 	p_description	IN OUT NOCOPY IGS_RU_DESCRIPTION.rule_description%TYPE )
1121 RETURN BOOLEAN IS
1122 BEGIN DECLARE
1123 	v_hash	NUMBER;
1124 BEGIN
1125 /*
1126 	 check if more to process
1127 */
1128 	IF p_description IS NULL
1129 	THEN
1130 		RETURN FALSE;
1131 	END IF;
1132 	p_action := NULL;
1133 	v_hash := INSTR(p_description, '#');
1134 	p_string := SUBSTR(p_description,1,v_hash - 1);
1135 	IF v_hash = 0
1136 	THEN
1137 		p_action := '';
1138 		p_string := p_description;
1139 	ELSE
1140 		FOR return_types IN (
1141 			SELECT	s_return_type
1142 			FROM	IGS_RU_RET_TYPE
1143 			WHERE	s_return_type LIKE SUBSTR(p_description,v_hash + 1,1)||'%'
1144 			ORDER BY s_return_type DESC )
1145 		LOOP
1146 			IF SUBSTR(p_description,v_hash + 1,LENGTH(return_types.s_return_type))
1147 				= return_types.s_return_type
1148 			THEN
1149 				p_action := return_types.s_return_type;
1150 				EXIT;
1151 			END IF;
1152 		END LOOP;
1153 		IF p_action IS NULL
1154 		THEN
1155 			Fnd_Message.Set_Name('IGS','IGS_GE_INVALID_OPER');
1156 			IGS_GE_MSG_STACK.ADD;
1157 		END IF;
1158 	END IF;
1159 	p_description := SUBSTR(p_description,v_hash + 1 + LENGTH(p_action));
1160 	RETURN TRUE;
1161 END;
1162 END breakdown_desc;
1163 /*
1164 
1165  count parameters in rule description
1166 
1167 */
1168 FUNCTION count_params(
1169 	p_rule_description	IN VARCHAR2)
1170 RETURN NUMBER IS
1171 BEGIN DECLARE
1172 	v_rule_description	IGS_RU_DESCRIPTION.rule_description%TYPE;
1173 	v_string		IGS_RU_DESCRIPTION.rule_description%TYPE;
1174 	v_action		IGS_RU_RET_TYPE.s_return_type%TYPE;
1175 	v_count			NUMBER := 0;
1176 BEGIN
1177 	v_rule_description := p_rule_description;
1178 	WHILE breakdown_desc(v_string,v_action,v_rule_description)
1179 	LOOP
1180 		IF v_action IS NOT NULL
1181 		THEN
1182 			v_count := v_count + 1;
1183 		END IF;
1184 	END LOOP;
1185 	RETURN v_count;
1186 END;
1187 END count_params;
1188 /*
1189 
1190  set and count the parameter types in RULE description
1191 
1192 */
1193 FUNCTION set_params(
1194 	p_rule_description	IN VARCHAR2)
1195 RETURN NUMBER IS
1196 BEGIN DECLARE
1197 	v_rule_description	IGS_RU_DESCRIPTION.rule_description%TYPE;
1198 	v_string		IGS_RU_DESCRIPTION.rule_description%TYPE;
1199 	v_action		IGS_RU_RET_TYPE.s_return_type%TYPE;
1200 	v_count			NUMBER := 0;
1201 BEGIN
1202 	v_rule_description := p_rule_description;
1203 	WHILE breakdown_desc(v_string,v_action,v_rule_description)
1204 	LOOP
1205 		IF v_action IS NOT NULL
1206 		THEN
1207 			v_count := v_count + 1;
1208 			gt_param_list(v_count) := v_action;
1209 		END IF;
1210 	END LOOP;
1211 	RETURN v_count;
1212 END;
1213 END set_params;
1214 /*
1215 
1216  check if this parameter type is allowed
1217 
1218 */
1219 FUNCTION valid_param_type (
1220 	p_return_type	IGS_RU_RET_TYPE.s_return_type%TYPE )
1221 RETURN BOOLEAN IS
1222 BEGIN
1223 	FOR v_ii IN 1 .. gv_params
1224 	LOOP
1225 		IF gt_param_list(v_ii) = p_return_type
1226 		THEN
1227 			RETURN TRUE;
1228 		END IF;
1229 	END LOOP;
1230 	RETURN FALSE;
1231 END valid_param_type;
1232 /*
1233 
1234  check if this parameter is of valid type
1235 
1236 */
1237 FUNCTION valid_param (
1238 	p_return_type	IGS_RU_RET_TYPE.s_return_type%TYPE,
1239 	p_param		NUMBER )
1240 RETURN BOOLEAN IS
1241 BEGIN
1242 	IF gt_param_list(p_param) = p_return_type
1243 	THEN
1244 		RETURN TRUE;
1245 	END IF;
1246 	RETURN FALSE;
1247 	EXCEPTION
1248 		WHEN NO_DATA_FOUND THEN
1249 			RETURN FALSE;
1250 END valid_param;
1251 /*
1252 
1253  cascade delete RULE items
1254  save RULE and set numbers
1255 
1256 */
1257 PROCEDURE delete_rule_items(
1258 	p_rule_number	IN IGS_RU_RULE.sequence_number%TYPE,
1259 	p_item		IN IGS_RU_ITEM.item%TYPE)
1260 IS
1261 		CURSOR c_rule_items IS
1262 		SELECT	rowid, ri.*
1263 		FROM	IGS_RU_ITEM  ri
1264 		WHERE	rul_sequence_number = p_rule_number
1265 		AND	item >= p_item ;
1266 
1267 		CURSOR c_rule (p_rule_number IN IGS_RU_ITEM.RULE_NUMBER%TYPE) IS
1268 		SELECT	rowid, rule.*
1269 		FROM	IGS_RU_RULE  rule
1270 		WHERE	sequence_number = p_rule_number;
1271 
1272 
1273 		CURSOR c_rule_set_mbr(p_set_number IN IGS_RU_ITEM.SET_NUMBER%TYPE) IS
1274 		SELECT	rowid, rsmbr.*
1275 		FROM	IGS_RU_SET_MEMBER  rsmbr
1276 		WHERE	rs_sequence_number =p_set_number;
1277 
1278 
1279 		CURSOR C_rule_set (p_set_number IN IGS_RU_ITEM.SET_NUMBER%TYPE) IS
1280 		SELECT	rowid, rs.*
1281 		FROM	IGS_RU_SET  rs
1282 		WHERE	sequence_number = p_set_number;
1283 
1284 
1285 BEGIN
1286 	FOR c_rule_items_REC IN c_rule_items	LOOP
1287 
1288 		IGS_RU_ITEM_PKG.DELETE_ROW (
1289 		X_ROWID => C_RULE_ITEMS_REC.ROWID );
1290 
1291 		IF c_rule_items_rec.rule_number IS NOT NULL
1292 		THEN
1293 /*
1294 			 save RULE number
1295 */
1296 			gv_rn_index := gv_rn_index + 1;
1297 			gt_rule_numbers(gv_rn_index) := c_rule_items_rec.rule_number;
1298 /*
1299 			 remove all items of this IGS_RU_RULE
1300 */
1301 			delete_rule_items(c_rule_items_rec.rule_number,0);
1302 /*
1303 			 remove RULE
1304 */
1305 			FOR c_rule_rec  IN c_rule (c_rule_items_rec.rule_number) LOOP
1306 				IGS_RU_RULE_PKG.DELETE_ROW (X_ROWID => C_RULE_REC.ROWID );
1307 			END LOOP;
1308 
1309 		ELSIF c_rule_items_rec.set_number IS NOT NULL
1310 		THEN
1311 /*
1312 			 save set number
1313 */
1314 			gv_sn_index := gv_sn_index + 1;
1315 			gt_set_numbers(gv_sn_index) := c_rule_items_rec.set_number;
1316 /*
1317 			 remove set members
1318 */
1319 			FOR c_rule_set_mbr_rec IN c_rule_set_mbr(c_rule_items_rec.set_number) LOOP
1320 				IGS_RU_SET_MEMBER_PKG.DELETE_ROW (X_ROWID => C_RULE_SET_MBR_REC.ROWID);
1321 			END LOOP;
1322 
1323 /*
1324 			 remove set
1325 */
1326 			FOR C_RULE_SET_REC IN C_RULE_SET(c_rule_items_rec.set_number) LOOP
1327 				IGS_RU_SET_PKG.DELETE_ROW (X_ROWID => C_RULE_SET_REC.ROWID );
1328 			END LOOP;
1329 
1330 		END IF;
1331 	END LOOP;
1332 END delete_rule_items;
1333 /*
1334 
1335  build and insert RULE item
1336  increment item if used
1337 
1338 */
1339 PROCEDURE make_rule_item(
1340 	p_from			IN VARCHAR2,
1341 	p_rule_num		IN NUMBER,
1342 	p_item			IN OUT NOCOPY NUMBER,
1343 	p_turin_function	IN IGS_RU_ITEM.turin_function%TYPE,
1344 	p_rud_seq_num		IN IGS_RU_DESCRIPTION.sequence_number%TYPE,
1345 	p_rule_number		IN IGS_RU_ITEM.rule_number%TYPE,
1346 	p_set_number		IN IGS_RU_ITEM.set_number%TYPE,
1347 	p_value			IN IGS_RU_ITEM.value%TYPE)
1348 IS
1349 BEGIN DECLARE
1350 	v_named_rule		IGS_RU_ITEM.named_rule%TYPE;
1351 	v_value			IGS_RU_ITEM.value%TYPE;
1352 	v_rule_description	IGS_RU_DESCRIPTION.rule_description%TYPE;
1353 	X_ROWID			VARCHAR2(25);
1354 BEGIN
1355 	IF p_generate_rule = FALSE
1356 	THEN
1357 		RETURN;
1358 	END IF;
1359 	delete_rule_items(p_rule_num,p_item);
1360 	v_value := p_value;
1361 	IF p_turin_function IS NOT NULL
1362 	THEN
1363 		v_value := NULL;
1364 	ELSIF p_rud_seq_num IS NOT NULL
1365 	THEN
1366 	BEGIN
1367 /*
1368 		 match to named RULE
1369 */
1370 		SELECT	rul_sequence_number
1371 		INTO	v_named_rule
1372 		FROM	IGS_RU_NAMED_RULE
1373 		WHERE	rud_sequence_number = p_rud_seq_num;
1374 /*
1375 		 set number of parameters for called RULE
1376 */
1377 		SELECT	rule_description
1378 		INTO	v_rule_description
1379 		FROM	IGS_RU_DESCRIPTION
1380 		WHERE	sequence_number = p_rud_seq_num;
1381 		v_value := count_params(v_rule_description);
1382 /*
1383 		 add evaluate RULE item
1384 */
1385 		make_rule_item('1',p_rule_num,p_item,
1386 			'_ER',
1387 			NULL,NULL,NULL,NULL);
1388 		EXCEPTION
1389 		WHEN NO_DATA_FOUND THEN
1390 			IF p_value IS NULL
1391 			THEN
1392 /*
1393 				 do nothing
1394 */
1395 				RETURN;
1396 			END IF;
1397 			v_named_rule := NULL;
1398 	END;
1399 	END IF;
1400 	IGS_RU_ITEM_PKG.INSERT_ROW (
1401 	X_ROWID			=>	X_ROWID,
1402 	X_RUL_SEQUENCE_NUMBER	=>	p_rule_num,
1403 	X_ITEM                  => 	p_item,
1404 	X_TURIN_FUNCTION        => 	p_turin_function,
1405 	X_NAMED_RULE            => 	v_named_rule,
1406 	X_RULE_NUMBER           => 	p_rule_number,
1407 	X_SET_NUMBER            => 	p_set_number,
1408 	X_VALUE                 => 	v_value,
1409 	X_DERIVED_RULE          => 	NULL );
1410 
1411 /*
1412 	 increment item
1413 */
1414 	p_item := p_item + 1;
1415 END;
1416 END make_rule_item;
1417 /*
1418 
1419  from an SQL select string match value or create a list of values
1420 
1421 */
1422 FUNCTION do_LOV (
1423 	p_rule		IN OUT NOCOPY	VARCHAR2,
1424 	p_rule_number	IN	NUMBER,
1425 	p_item		IN OUT NOCOPY	NUMBER,
1426 	p_select_string	IN	VARCHAR2 )
1427 RETURN BOOLEAN IS
1428 	v_select_string	VARCHAR2(2000);
1429 	v_cursor	INTEGER;
1430 	v_rows		INTEGER;
1431 	v_value		VARCHAR2(100);
1432 	v_description	VARCHAR2(100);
1433 	v_count		NUMBER := 0;
1434 BEGIN
1435 /*
1436 	 replace previously selected field(s) with their values
1437 */
1438 	v_select_string := REPLACE(p_select_string,'$PREV',gv_prev);
1439 	v_select_string := REPLACE(v_select_string,'$PPREV',gv_pprev);
1440 	v_cursor := DBMS_SQL.OPEN_CURSOR;
1441 	DBMS_SQL.PARSE(v_cursor,v_select_string||' ORDER BY 1 DESC',dbms_sql.native);
1442 	DBMS_SQL.DEFINE_COLUMN(v_cursor,1,v_value,100);
1443 	DBMS_SQL.DEFINE_COLUMN(v_cursor,2,v_description,100);
1444 	v_rows := DBMS_SQL.EXECUTE(v_cursor);
1445 	WHILE DBMS_SQL.FETCH_ROWS(v_cursor) > 0
1446 	LOOP
1447 		v_count := v_count + 1;
1448 		DBMS_SQL.COLUMN_VALUE(v_cursor,1,v_value);
1449 		IF match_string_to_rule(v_value,p_rule)
1450 		THEN
1451 /*
1452 			 add selected value
1453 */
1454 			make_rule_item('do_LOV',p_rule_number,p_item,
1455 				NULL,NULL,NULL,NULL,
1456 				v_value);
1457 /*
1458 			 set previous selected values
1459 */
1460 			gv_pprev := gv_prev;
1461 			gv_prev := v_value;
1462 			DBMS_SQL.CLOSE_CURSOR(v_cursor);
1463 			RETURN TRUE;
1464 		END IF;
1465 		DBMS_SQL.COLUMN_VALUE(v_cursor,2,v_description);
1466 		make_LOV(p_rule,v_value,v_description,'Y');
1467 	END LOOP;
1468 	DBMS_SQL.CLOSE_CURSOR(v_cursor);
1469 	IF v_count = 0
1470 	THEN
1471 		make_LOV(p_rule,
1472 			'*** No values selected ***',
1473 			'ERROR:No values selected while attempting '||
1474 				'match from a database defined LOV''s.',
1475 			'N');
1476 	END IF;
1477 	RETURN FALSE;
1478 END do_LOV;
1479 
1480 /*
1481 
1482  from an SQL select string match value, create set member or
1483  create a list of values
1484 
1485 */
1486 FUNCTION make_set (
1487 	p_rule		IN OUT NOCOPY	VARCHAR2,
1488 	p_rule_number	IN	NUMBER,
1489 	p_item		IN OUT NOCOPY	NUMBER,
1490 	p_select_string	IN	VARCHAR2 )
1491 RETURN BOOLEAN IS
1492 	v_select_string	VARCHAR2(2000);
1493 	v_cursor	INTEGER;
1494 	v_rows		INTEGER;
1495 	v_value		VARCHAR2(100);
1496 	v_description	VARCHAR2(100);
1497 	v_count		NUMBER := 0;
1498 BEGIN
1499 /*
1500 	 replace previously selected field(s) with their values
1501 */
1502 	v_select_string := REPLACE(p_select_string,'$PREV',gv_prev);
1503 	v_select_string := REPLACE(v_select_string,'$PPREV',gv_pprev);
1504 	v_cursor := DBMS_SQL.OPEN_CURSOR;
1505 	DBMS_SQL.PARSE(v_cursor,v_select_string||' ORDER BY 1 DESC',dbms_sql.v7);
1506 	DBMS_SQL.DEFINE_COLUMN(v_cursor,1,v_value,100);
1507 	DBMS_SQL.DEFINE_COLUMN(v_cursor,2,v_description,100);
1508 	v_rows := DBMS_SQL.EXECUTE(v_cursor);
1509 	WHILE DBMS_SQL.FETCH_ROWS(v_cursor) > 0
1510 	LOOP
1511 		v_count := v_count + 1;
1512 		DBMS_SQL.COLUMN_VALUE(v_cursor,1,v_value);
1513 		IF match_string_to_rule(v_value,p_rule)
1514 		THEN
1515 			DBMS_SQL.CLOSE_CURSOR(v_cursor);
1516 			RETURN TRUE;
1517 		END IF;
1518 		DBMS_SQL.COLUMN_VALUE(v_cursor,2,v_description);
1519 		make_LOV(p_rule,v_value,v_description,'Y');
1520 	END LOOP;
1521 	DBMS_SQL.CLOSE_CURSOR(v_cursor);
1522 	IF v_count = 0
1523 	THEN
1524 		make_LOV(p_rule,
1525 			'*** No values selected ***',
1526 			'ERROR:No values selected while attempting '||
1527 				'match from a database defined LOV''s.',
1528 			'N');
1529 	END IF;
1530 	RETURN FALSE;
1531 END make_set;
1532 /*
1533 
1534  parse RULE stage two
1535 
1536 */
1537 FUNCTION parse_rule2(
1538 	p_type		IN VARCHAR2,
1539 	p_rule		IN OUT NOCOPY VARCHAR2,
1540 	p_rule_number	IN NUMBER,
1541 	p_item		IN OUT NOCOPY NUMBER)
1542 RETURN BOOLEAN IS
1543 BEGIN DECLARE
1544 	v_rule			VARCHAR2(2000);
1545 	v_string		IGS_RU_DESCRIPTION.rule_description%TYPE;
1546 	v_action		IGS_RU_RET_TYPE.s_return_type%TYPE;
1547 	v_rule_description	IGS_RU_DESCRIPTION.rule_description%TYPE;
1548 	v_number		NUMBER;
1549 	v_item			NUMBER;
1550 	v_first			BOOLEAN;
1551 BEGIN
1552 /*
1553 	 save RULE
1554 */
1555 	v_rule := p_rule;
1556 /*
1557 	 save index
1558 */
1559 	v_item := p_item;
1560 /*
1561 	 select all descriptions where the first description item <> return type
1562 */
1563 	FOR rule_descriptions IN (
1564 		SELECT	RUD.sequence_number,
1565 			s_turin_function,
1566 			rule_description,
1567 			description
1568 		FROM	IGS_RU_DESCRIPTION	RUD,
1569 			IGS_RU_GROUP_SET		RGS
1570 		WHERE	s_return_type = p_type
1571 		AND	rule_description NOT LIKE '#'||p_type||'%'
1572 		AND	RUD.sequence_number = RGS.rud_sequence_number
1573 		AND	RGS.rug_sequence_number = p_group
1574 		ORDER BY rule_description DESC )
1575 	LOOP
1576 		v_rule_description := rule_descriptions.rule_description;
1577 		v_first := TRUE;
1578 		WHILE breakdown_desc(v_string,v_action,v_rule_description)
1579 		LOOP
1580 /*
1581 			 only do parameter if applicable
1582 */
1583 			IF rule_descriptions.s_turin_function = '$'
1584 			THEN
1585 				IF valid_param_type(p_type)
1586 				THEN
1587 					gv_param_type := p_type;
1588 				ELSE
1589 					EXIT; /* while, get next description  */
1590 				END IF;
1591 			END IF;
1592 			IF p_type = 'PARAM_NUMS'
1593 			THEN
1594 				IF NOT valid_param(gv_param_type,v_string)
1595 				THEN
1596 					EXIT; /* while, get next description  */
1597 				END IF;
1598 			END IF;
1599 /*
1600 			 do list of values select thingo
1601 */
1602 			IF v_action = '[LOV]'
1603 			THEN
1604 				RETURN do_LOV(p_rule,p_rule_number,
1605 					      p_item,v_rule_description);
1606 /*
1607 	 do generic set stuff determined from SQL
1608 */
1609 			ELSIF v_action = '[GS_MBR]'
1610 			THEN
1611 				RETURN make_set(p_rule,p_rule_number,
1612 					        p_item,v_rule_description);
1613 
1614 			ELSIF v_action = '[ASCII]' OR v_action = '[DATE]'
1615 			THEN
1616 /*
1617 				 set termiate string character
1618 */
1619 				gv_string_terminate := v_string;
1620 			END IF;
1621 			IF v_string IS NOT NULL
1622 			THEN
1623 /*
1624 				 string [action]
1625 */
1626 				IF match_string_to_rule(v_string,p_rule)
1627 				THEN
1628 /*
1629 					 found match, follow this path
1630 */
1631 					IF v_first
1632 					THEN
1633 						IF v_action IS NULL
1634 						THEN
1635 /*
1636 							 turin function, named RULE or value
1637 */
1638 							make_rule_item('2',p_rule_number,p_item,
1639 								rule_descriptions.s_turin_function,
1640 								rule_descriptions.sequence_number,
1641 								NULL,NULL,
1642 								v_string);
1643 						ELSE
1644 /*
1645 							 turin function, named RULE or intermediate action
1646 */
1647 							make_rule_item('3',p_rule_number,p_item,
1648 								rule_descriptions.s_turin_function,
1649 								rule_descriptions.sequence_number,
1650 								NULL,NULL,NULL);
1651 						END IF;
1652 					END IF;
1653 					IF v_action IS NOT NULL
1654 					THEN
1655 						IF parse_rule(v_action,p_rule,p_rule_number,p_item)
1656 						THEN
1657 							IF v_rule_description IS NULL
1658 							THEN
1659 								RETURN TRUE;
1660 							END IF;
1661 						ELSE
1662 							EXIT;  /* while, next description */
1663 						END IF;
1664 					ELSE
1665 /*
1666 						 no more description
1667 */
1668 						RETURN TRUE;
1669 					END IF;
1670 				ELSE
1671 					make_LOV(p_rule,v_string,
1672 						rule_descriptions.description,'Y');
1673 					EXIT; /* while, next description */
1674 				END IF;
1675 			ELSIF v_action IS NOT NULL
1676 			THEN
1677 /*
1678 				 action only
1679 				 lt,lte,eq,neq,gte,gt #ALLOWED_TYPE
1680 */
1681 				make_rule_item('4',p_rule_number,p_item,
1682 					rule_descriptions.s_turin_function,
1683 					rule_descriptions.sequence_number,
1684 					NULL,NULL,NULL);
1685 				IF parse_rule(v_action,p_rule,p_rule_number,p_item)
1686 				THEN
1687 					IF v_rule_description IS NULL
1688 					THEN
1689 						RETURN TRUE;
1690 					END IF;
1691 				ELSE
1692 /*
1693 					 allow for number RETURN FALSE;
1694 */
1695 					EXIT;
1696 				END IF;
1697 			END IF;
1698 			v_first := FALSE;
1699 		END LOOP;
1700 /*		 restore RULE for next option   */
1701 		p_rule := v_rule;
1702 /*		 restore index for next option  */
1703 		p_item := v_item;
1704 	END LOOP;
1705 	RETURN FALSE;
1706 END;
1707 END parse_rule2;
1708 /*
1709  parse RULE
1710 */
1711 FUNCTION parse_rule(
1712 	p_type		IN VARCHAR2,
1713 	p_rule		IN OUT NOCOPY VARCHAR2,
1714 	p_rule_number	IN NUMBER,
1715 	p_item		IN OUT NOCOPY NUMBER)
1716 RETURN BOOLEAN IS
1717 BEGIN DECLARE
1718 	v_rule			VARCHAR2(2000);
1719 	v_string		VARCHAR2(2000);
1720 	v_action		IGS_RU_RET_TYPE.s_return_type%TYPE;
1721 	v_rule_description	IGS_RU_DESCRIPTION.rule_description%TYPE;
1722 	v_first_action		BOOLEAN;
1723 	v_return		BOOLEAN;
1724 	v_item			NUMBER;
1725 	v_new_rule		NUMBER;
1726 	v_new_item		NUMBER;
1727 	v_type			IGS_RU_RET_TYPE.s_return_type%TYPE;
1728 	v_evaluate		BOOLEAN;
1729 	v_number		NUMBER;
1730 	v_set_type		IGS_RU_SET.set_type%TYPE;
1731 	v_next_action		IGS_RU_RET_TYPE.s_return_type%TYPE;
1732 BEGIN
1733 /*
1734 	 special actions
1735 */
1736 	IF SUBSTR(p_type,1,5) = '[0-9]'
1737 	THEN
1738 		IF get_number(v_number,p_rule) = TRUE
1739 		THEN
1740 			IF SUBSTR(p_type,6) IS NULL OR
1741 			   SUBSTR(p_type,6) <> ':VERIFY'
1742 			THEN
1743 /*
1744 				 add number
1745 */
1746 				make_rule_item('5',p_rule_number,p_item,
1747 					NULL,NULL,NULL,NULL,
1748 					v_number);
1749 			END IF;
1750 			RETURN TRUE;
1751 		ELSE
1752 			make_LOV(p_rule,'*** A Number ***',
1753 				'Input a number.','N');
1754 			RETURN FALSE;
1755 		END IF;
1756 	ELSIF SUBSTR(p_type,1,7) = '[ASCII]'
1757 	THEN
1758 /*
1759 		 this assumes terminate string is same as commencement string?
1760 */
1761 		IF get_string(v_string,p_rule,gv_string_terminate) = TRUE
1762 		THEN
1763 /*
1764 			 add string
1765 */
1766 			make_rule_item('5.1',p_rule_number,p_item,
1767 				NULL,NULL,NULL,NULL,
1768 				v_string);
1769 			RETURN TRUE;
1770 		ELSE
1771 			make_LOV(p_rule,'*** A String ***',
1772 				'Input any text.','N');
1773 			RETURN FALSE;
1774 		END IF;
1775 	ELSIF SUBSTR(p_type,1,6) = '[DATE]'
1776 	THEN
1777 		IF get_date(v_string,p_rule) = TRUE
1778 		THEN
1779 /*
1780 			 add date
1781 */
1782 			make_rule_item('5.1',p_rule_number,p_item,
1783 				NULL,NULL,NULL,NULL,
1784 				v_string);
1785 			RETURN TRUE;
1786 		ELSE
1787 			make_LOV(p_rule,'*** A Date ***',
1788 				'Input a valid date.','N');
1789 			RETURN FALSE;
1790 		END IF;
1791 /*
1792 	 SET RELATED CODE
1793 	 all set types are described as (only change lower case fields to suit)
1794 		set_name		{#[SET]set_type}
1795 		set_type		#[MEMBER]set_member
1796 		set_type		#[MEMBER]set_member,set_type
1797 		set_member		#[set_cd]
1798 		set_member		#[set_cd].#VERSIONS
1799 	 new set
1800 */
1801 	ELSIF SUBSTR(p_type,1,5) = '[SET]'
1802 	THEN
1803 /*
1804 		 get set type/next action
1805 		 set type is restricted to 10 chars
1806 */
1807 		v_set_type := SUBSTR(p_type,6);
1808 		v_next_action := v_set_type;
1809 		gv_set_number := new_set(v_set_type);
1810 		IF parse_rule(v_next_action,p_rule,p_rule_number,p_item)
1811 		THEN
1812 /*
1813 			 add set number
1814 */
1815 			make_rule_item('6',p_rule_number,p_item,
1816 				NULL,NULL,NULL,
1817 				gv_set_number,
1818 				NULL);
1819 			RETURN TRUE;
1820 		ELSE
1821 			RETURN FALSE;
1822 		END IF;
1823 /*
1824 	 make set member
1825 */
1826 	ELSIF SUBSTR(p_type,1,8) = '[MEMBER]'
1827 	THEN
1828 		v_rule := p_rule;
1829 /*
1830 		 get next action
1831 */
1832 		v_next_action := SUBSTR(p_type,9);
1833 		IF parse_rule(v_next_action,p_rule,p_rule_number,p_item)
1834 		THEN
1835 			insert_set_member(gv_set_number,
1836 					SUBSTR(v_rule,1,LENGTH(v_rule) - LENGTH(p_rule)));
1837 			RETURN TRUE;
1838 		ELSE
1839 			RETURN FALSE;
1840 		END IF;
1841 /*
1842 	 consume set member, make LOV's
1843 	 one per set type
1844 */
1845 	ELSIF p_type = '[UNIT_CD]'
1846 	THEN
1847 		RETURN consume_unit_code(p_rule);
1848 	ELSIF p_type = '[US_CD]'
1849 	THEN
1850 		RETURN consume_us_code(p_rule);
1851 	ELSIF p_type = '[COURSE_CD]'
1852 	THEN
1853 		RETURN consume_crs_code(p_rule);
1854 /*
1855 	 SUB RULE CODE
1856 */
1857 	ELSIF SUBSTR(p_type,1,5) = 'RULE.'
1858 	THEN
1859 /*
1860 		 make new sub-RULE
1861 */
1862 		v_type := SUBSTR(p_type,6);
1863 		IF SUBSTR(v_type,1,5) = 'EVAL.'
1864 		THEN
1865 /*
1866 			 evaluate RULE
1867 */
1868 			v_type := SUBSTR(v_type,6);
1869 			v_evaluate := TRUE;
1870 		ELSE
1871 			v_evaluate := FALSE;
1872 		END IF;
1873 		v_new_rule := new_rule;
1874 		v_new_item := 1;
1875 		IF parse_rule(v_type,p_rule,v_new_rule,v_new_item)
1876 		THEN
1877 			IF v_evaluate
1878 			THEN
1879 /*
1880 				 add evaluate RULE item
1881 */
1882 				make_rule_item('7',p_rule_number,p_item,
1883 					'_ER',
1884 					NULL,NULL,NULL,NULL);
1885 			END IF;
1886 			make_rule_item('8',p_rule_number,p_item,
1887 				NULL,NULL,
1888 				v_new_rule,
1889 				NULL,gv_params);
1890 			RETURN TRUE;
1891 		END IF;
1892 		RETURN FALSE;
1893 	END IF;
1894 	gv_level := gv_level + 1;
1895 /*
1896 	 save RULE
1897 */
1898 	v_rule := p_rule;
1899 /*
1900 	 save index
1901 */
1902 	v_item := p_item;
1903 /*
1904 	 select all descriptions where the first description item = return type
1905 */
1906 	FOR rule_descriptions IN (
1907 		SELECT	RUD.sequence_number,
1908 			s_turin_function,
1909 			rule_description,
1910 			description
1911 		FROM	IGS_RU_DESCRIPTION	RUD,
1912 			IGS_RU_GROUP_SET		RGS
1913 		WHERE	s_return_type = p_type
1914 		AND	rule_description LIKE '#'||p_type||'%'
1915 		AND	RUD.sequence_number = RGS.rud_sequence_number
1916 		AND	RGS.rug_sequence_number = p_group
1917 		ORDER BY rule_description DESC )
1918 	LOOP
1919 		v_rule_description := rule_descriptions.rule_description;
1920 		v_first_action := TRUE;
1921 		WHILE breakdown_desc(v_string,v_action,v_rule_description)
1922 		LOOP
1923 			IF v_string IS NOT NULL
1924 			THEN
1925 /*
1926 				 string [action]
1927 */
1928 				IF match_string_to_rule(v_string,p_rule)
1929 				THEN
1930 					IF v_action IS NOT NULL
1931 					THEN
1932 						IF parse_rule(v_action,p_rule,p_rule_number,p_item)
1933 						THEN
1934 							IF v_rule_description IS NULL
1935 							THEN
1936 								gv_level := gv_level - 1;
1937 								RETURN TRUE;
1938 							END IF;
1939 						ELSE
1940 							gv_level := gv_level - 1;
1941 							RETURN FALSE;
1942 						END IF;
1943 					ELSE
1944 /*
1945 						 no more description
1946 */
1947 						gv_level := gv_level - 1;
1948 						RETURN TRUE;
1949 					END IF;
1950 				ELSE
1951 					make_LOV(p_rule,v_string,
1952 						rule_descriptions.description,'Y');
1953 					EXIT;  /* while, next description */
1954 				END IF;
1955 			ELSIF v_action IS NOT NULL
1956 			THEN
1957 /*
1958 				 first and subsequent action
1959 				 or,and,divide,sutract,plus,mult #ALLOWED_TYPE
1960 */
1961 				make_rule_item('9',p_rule_number,p_item,
1962 					rule_descriptions.s_turin_function,
1963 					rule_descriptions.sequence_number,
1964 					NULL,NULL,NULL);
1965 				IF v_first_action
1966 				THEN
1967 /*
1968 					 #THIS_TYPE etc
1969 */
1970 					IF parse_rule2(v_action,p_rule,p_rule_number,p_item)
1971 					THEN
1972 						IF v_rule_description IS NULL
1973 						THEN
1974 							gv_level := gv_level - 1;
1975 							RETURN TRUE;
1976 						END IF;
1977 					ELSE
1978 						gv_level := gv_level - 1;
1979 						RETURN FALSE;
1980 					END IF;
1981 				ELSE
1982 					IF parse_rule(v_action,p_rule,p_rule_number,p_item)
1983 					THEN
1984 						IF v_rule_description IS NULL
1985 						THEN
1986 							gv_level := gv_level - 1;
1987 							RETURN TRUE;
1988 						END IF;
1989 					ELSE
1990 						gv_level := gv_level - 1;
1991 						RETURN FALSE;
1992 					END IF;
1993 				END IF;
1994 			END IF;
1995 			v_first_action := FALSE;
1996 
1997   END LOOP;
1998 /*
1999 		 restore RULE for next option
2000 */
2001 		p_rule := v_rule;
2002 /*
2003 		 restore index for next option
2004 */
2005 		p_item := v_item;
2006 	END LOOP;
2007 /*
2008 	 no success therefor try rest of TYPE
2009 */
2010 	v_return := parse_rule2(p_type,p_rule,p_rule_number,p_item);
2011 	gv_level := gv_level - 1;
2012 	RETURN v_return;
2013 END;
2014 END parse_rule;
2015 /*
2016 Preserve spaces of user defined codes
2017 */
2018 /* This following function has been added by nshee on 24-JUL-2002 as part of fix for bug:2395891
2019 Changes are:
2020         v_unit := UPPER(REPLACE(v_unit,cst_spacemod,' '));added this line by nshee as fix for bug 2395891 to insert back the space at the right places to validate with the DB record.
2021        WHERE	unit_set_cd LIKE UPPER(SUBSTR(p_rule,1,v_ii - 1)); commented by nshee as part of fix of bug 2381638 and 2395891 and added the next line  to validate the DB record correctly.
2022        WHERE	unit_set_cd LIKE UPPER(SUBSTR(REPLACE(p_rule,cst_spacemod,' '),1,v_ii - 1));
2023       Earlier,  In case the user defined program code or the milestone type has an internal space in the code
2024       itself, it was removing the same too. However, the parsing was succesful since the spaces are removed from the
2025       database record too before the parsing. However, the record was not getting back the spaces later and hence the problem was happening.
2026 
2027      The string manipulation done in the function is a little complex in logic. There is a chance that the logic doesn't cater to all complexities that might arise later,
2028      it is best suggested that the user defined setup codes should not have any internal space whatsoever.
2029      In case, one needs to revert it back to the earlier state, here is what you need to do.
2030      1) remove the following line in the procedure unit insert_set_member.
2031         v_unit := UPPER(REPLACE(v_unit,cst_spacemod,' '));added this line by nshee as fix for bug 2395891 to insert back the space at the right places to validate with the DB record.
2032      2) Remove the call to this function below and comment out NOCOPY the entire Function of pres_space begin to end.
2033      3) remove all declarations of cst_spacemod within this package along with the following variables in the declaration section
2034      4) Uncomment the line added in FUNCTION consume_us_code and remove the line added
2035      5) Compile the package in the DB again...enjoy.
2036 */
2037 FUNCTION pres_space (v_str IN VARCHAR2) RETURN VARCHAR2 AS
2038   v_out_str VARCHAR2(2000);
2039   v_desired_str VARCHAR2(2000);
2040   TYPE rec_pos IS RECORD (start_pos NUMBER, end_pos NUMBER);
2041   TYPE tab_str IS TABLE OF VARCHAR2(1000) INDEX BY BINARY_INTEGER;
2042   TYPE tab_pos IS TABLE OF rec_pos INDEX BY BINARY_INTEGER;
2043   v_tab_str   tab_str;
2044   ctr BINARY_INTEGER := 1;
2045   v_tab_str_f tab_str;
2046   ctr_f BINARY_INTEGER := 1;
2047   v_tab_pos tab_pos;
2048   ctr_pos BINARY_INTEGER := 1;
2049   v_tab_pos_f tab_pos;
2050   ctr_pos_f BINARY_INTEGER := 1;
2051   v_curly NUMBER:=0;
2052   v_start_pos NUMBER;
2053   v_end_pos NUMBER;
2054   v_out_str1 VARCHAR2(4000);
2055   v_start BOOLEAN DEFAULT FALSE;
2056 
2057   PROCEDURE putarray (p_chr VARCHAR2, p_curly NUMBER) IS
2058   BEGIN
2059      IF p_curly >= 1 AND p_chr = ' '  THEN
2060        v_tab_str(ctr) := cst_spacemod;
2061        ctr := ctr +1;
2062      ELSE
2063        v_tab_str(ctr) := p_chr;
2064        ctr := ctr +1;
2065      END IF;
2066   END putarray;
2067 
2068 BEGIN
2069 FOR i IN 1..LENGTH(v_str) LOOP
2070     IF substr(v_str,i,1) = '{' THEN
2071        v_curly := v_curly + 1;
2072     ELSIF substr(v_str,i,1) = '}' AND v_curly >= 1 THEN
2073        v_curly := v_curly - 1;
2074     END IF;
2075     putarray (substr(v_str,i,1),v_curly);
2076 END LOOP;
2077 -- print the v_tab_str
2078 FOR i IN v_tab_str.FIRST..v_tab_str.LAST LOOP
2079    v_out_str := v_out_str || v_tab_str(i);
2080 END LOOP;
2081 IF instr(v_out_str,cst_spacemod) = 0 THEN
2082     v_desired_str := v_out_str;
2083     RETURN v_desired_str;
2084 END IF;
2085 FOR i IN v_tab_str.FIRST..v_tab_str.LAST LOOP
2086     IF v_tab_str(i) = cst_spacemod THEN
2087   v_tab_str_f (ctr_f) := IGS_GE_NUMBER.TO_CANN(i);
2088   ctr_f := ctr_f+1;
2089     END IF;
2090 END LOOP;
2091 FOR i IN v_tab_str_f.FIRST..v_tab_str_f.LAST LOOP
2092    v_out_str1 := v_out_str1 || v_tab_str_f(i);
2093 END LOOP;
2094 FOR i IN v_tab_str_f.FIRST..v_tab_str_f.LAST LOOP
2095     IF v_tab_str(IGS_GE_NUMBER.TO_NUM(v_tab_str_f(i))-1) = '{' OR
2096     v_tab_str(IGS_GE_NUMBER.TO_NUM(v_tab_str_f(i))-1) NOT IN (cst_spacemod) THEN
2097        v_start_pos := IGS_GE_NUMBER.TO_NUM(v_tab_str_f(i));
2098     END IF;
2099     IF v_tab_str(IGS_GE_NUMBER.TO_NUM(v_tab_str_f(i))+1) NOT IN (cst_spacemod) THEN
2100        v_end_pos := IGS_GE_NUMBER.TO_NUM(v_tab_str_f(i));
2101     END IF;
2102     IF v_start_pos IS NOT NULL OR v_end_pos is NOT NULL THEN
2103        IF v_start_pos IS NOT NULL THEN
2104           v_tab_pos(ctr_pos).start_pos := v_start_pos;
2105           v_start := TRUE;
2106        END IF;
2107        IF v_end_pos IS NOT NULL AND v_start THEN
2108           v_tab_pos(ctr_pos).end_pos := v_end_pos;
2109           v_start := FALSE;
2110        END IF;
2111        IF v_tab_pos(ctr_pos).end_pos IS NOT NULL AND
2112           v_tab_pos(ctr_pos).start_pos IS NOT NULL THEN
2113           ctr_pos := ctr_pos +1;
2114        END IF;
2115     END IF;
2116     v_start_pos := NULL;
2117     v_end_pos := NULL;
2118 END LOOP;
2119 -- filter out NOCOPY unwanted rows from v_tab_pos
2120 FOR i IN v_tab_pos.FIRST..v_tab_pos.LAST LOOP
2121     IF (v_tab_str(IGS_GE_NUMBER.TO_NUM(v_tab_pos(i).start_pos) - 1) = '{' OR
2122          v_tab_str(IGS_GE_NUMBER.TO_NUM(v_tab_pos(i).end_pos) +1) = '}') OR
2123         (v_tab_str(IGS_GE_NUMBER.TO_NUM(v_tab_pos(i).start_pos) - 1) = ',' OR
2124         v_tab_str(IGS_GE_NUMBER.TO_NUM(v_tab_pos(i).end_pos) +1) = ',')THEN
2125         v_tab_pos_f(ctr_pos_f).start_pos := v_tab_pos(i).start_pos;
2126         v_tab_pos_f(ctr_pos_f).end_pos := v_tab_pos(i).end_pos;
2127         ctr_pos_f := ctr_pos_f + 1;
2128     END IF;
2129 END LOOP;
2130   v_desired_str := v_out_str;
2131 -- now loop the tab v_tab_pos_f to get the desired output
2132 IF v_tab_pos_f.COUNT = 0 THEN
2133   RETURN v_desired_str;
2134 END IF;
2135 FOR i IN v_tab_pos_f.FIRST..v_tab_pos_f.LAST LOOP
2136     v_desired_str := substr(v_desired_str,1,v_tab_pos_f(i).start_pos-1)||rpad(' ',(v_tab_pos_f(i).end_pos-v_tab_pos_f(i).start_pos)+1)||substr(v_desired_str,v_tab_pos_f(i).end_pos+1);
2137 END LOOP;
2138 RETURN v_desired_str;
2139 END pres_space;
2140 /*
2141  rulp_ins_parser
2142 */
2143 BEGIN DECLARE
2144 	v_input_rule	VARCHAR2(2000);
2145 	v_rule		VARCHAR2(2000);
2146 	v_return	BOOLEAN;
2147 	v_item		NUMBER;
2148 	v_rule_length	NUMBER;
2149 	v_loop_count	NUMBER := 1;
2150 CURSOR C_RNR IS
2151 	SELECT ROWID, rnr.*
2152 	FROM   IGS_RU_NAMED_RULE rnr
2153 	WHERE	rul_sequence_number = p_rule_number;
2154 
2155 BEGIN
2156 	v_input_rule := p_rule_processed||p_rule_unprocessed;
2157 	gv_params := set_params(p_rule_description);
2158 	IF p_generate_rule = TRUE
2159 	THEN
2160 /*
2161 		 new RULE uses index
2162 */
2163 		gv_rn_index := 0;
2164 		gv_sn_index := 0;
2165 		IF p_rule_number IS NULL
2166 		THEN
2167 			p_rule_number := new_rule;
2168 		END IF;
2169 	END IF;
2170 /*
2171 	 loop until more than 1 item to select
2172 */
2173 	LOOP
2174 		IF p_generate_rule = TRUE
2175 		THEN
2176 			gv_rn_index := 0;
2177 			gv_sn_index := 0;
2178 			delete_rule_items(p_rule_number,0);
2179 		END IF;
2180 /*
2181 		 initialise for parser
2182 */
2183 		gv_level := -1;
2184 		gv_min_rule := 2000;
2185 		gv_LOV_index := 0;
2186 		v_item := 1;
2187 /*
2188 		 replace all real spaces with internal spaces
2189 */
2190 --		v_rule := REPLACE(v_input_rule,' ',cst_space);
2191 /* Start of the call to the function pres_space for bug 2395891 by nshee*/
2192 IF v_input_rule IS NULL THEN
2193   v_rule := REPLACE(v_input_rule,' ',cst_space);
2194 ELSE
2195     v_rule:= REPLACE(pres_space(v_input_rule),' ',cst_space);
2196 END IF;
2197 /* End of the call to the function pres_space for bug 2395891 by nshee*/
2198 		v_return := parse_rule(p_return_type,v_rule,p_rule_number,v_item);
2199 		IF v_return = TRUE
2200 		THEN
2201 			make_LOV(v_rule,'*** Parse Successful ***',
2202 				'The rule has been successfully completed.','N');
2203 		END IF;
2204 /*
2205 		 limit the number of parses for safety
2206 */
2207 		v_loop_count := v_loop_count + 1;
2208 		IF v_loop_count > 8
2209 		THEN
2210 			EXIT;
2211 		END IF;
2212 /*
2213 		 build select from list
2214 */
2215 		insert_LOV_tab;
2216 /*
2217 		 on more than one item EXIT
2218 */
2219 		IF LOV_item IS NULL
2220 		THEN
2221 			EXIT;
2222 		END IF;
2223 /*
2224 		 on error, left over RULE
2225 */
2226 		IF gv_min_rule <> 0
2227 		THEN
2228 			EXIT;
2229 		END IF;
2230 /*
2231 		 append the single item to RULE
2232 */
2233 		v_input_rule := v_input_rule||' '||LOV_item;
2234 	END LOOP;
2235 /*
2236 	 separate processed and unprocessed portions of RULE
2237 */
2238 	v_rule_length := LENGTH(v_input_rule);
2239 	p_rule_processed := SUBSTR(v_input_rule,1,v_rule_length - gv_min_rule);
2240 	p_rule_unprocessed := SUBSTR(v_input_rule,v_rule_length - gv_min_rule
2241 					+ 1 /* + gv_select_count */);
2242 /*
2243 	 display_LOV;
2244 */
2245 	IF p_generate_rule = TRUE
2246 	THEN
2247 /*
2248 		 update RULE text if it exists
2249 */
2250 		v_rule := IGS_RU_GEN_006.rulp_get_rule(p_rule_number);
2251 
2252 		FOR C_RNR_REC IN C_RNR LOOP
2253 		    IGS_RU_NAMED_RULE_PKG.UPDATE_ROW (
2254 			X_ROWID 			=> C_RNR_REC.ROWID,
2255 			X_RUL_SEQUENCE_NUMBER   => C_RNR_REC.RUL_SEQUENCE_NUMBER,
2256 			X_RUD_SEQUENCE_NUMBER   => C_RNR_REC.RUD_SEQUENCE_NUMBER,
2257 			X_MESSAGE_RULE          => C_RNR_REC.MESSAGE_RULE,
2258 			X_RUG_SEQUENCE_NUMBER   => C_RNR_REC.RUG_SEQUENCE_NUMBER,
2259 			X_RULE_TEXT             => v_rule  );
2260  		END LOOP;
2261 
2262 	END IF;
2263 	RETURN v_return;
2264 END;
2265 END rulp_ins_parser;
2266 
2267 END IGS_RU_GEN_002;